Friday, December 24, 2010

Configuring OpenLDAP with SSL/TLS on Debian

It is recommended that communication between clients and ldap server be encrypted. Before we enable encryption for ldap server we need SSL private key and certificate signed by certificate authority. Have a look at OpenSSL Certificates. Suppose here are your files: and


  1. Install CA certificate:
    cp ~/ca/demoCA/cacert.pem /etc/ssl/certs/
    chmod go+r /etc/ssl/certs/cacert.pem
  2. Copy ldap key and certificate files to /etc/ldap/ssl
    mkdir /etc/ldap/ssl/
    cp ~/ca/*.pem /etc/ldap/ssl/
  3. Secure certificates:
    ldap1:~# chown -R root:openldap /etc/ldap/ssl
    ldap1:~# chmod -R o-rwx /etc/ldap/ssl
  4. Enable ldaps protocol (file /etc/default/slapd)
    LAPD_SERVICES="ldap:// ldaps:/// ldapi:///"
  5. Create tls configuration file (tls-config.ldif):
    dn: cn=config
    add: olcTLSCACertificateFile
    olcTLSCACertificateFile: /etc/ssl/certs/cacert.pem
    add: olcTLSCertificateFile
    olcTLSCertificateFile: /etc/ldap/ssl/
    add: olcTLSCertificateKeyFile
    olcTLSCertificateKeyFile: /etc/ldap/ssl/
  6. Apply it:
    ldapmodify -QY EXTERNAL -H ldapi:/// -f tls-config.ldif
  7. Restart slapd:
    /etc/init.d/slapd restart
  8. Ensure started:
    netstat -tunlp | grep slapd
    tcp        0      0   *               LISTEN      2462/slapd      
    tcp        0      0 *               LISTEN      2462/slapd  


  1. Install ldap-utils package:
    apt-get install ldap-utils
  2. Configure (file /etc/ldap/ldap.conf)
    BASE    dc=dev,dc=local
    URI     ldaps://
    TLS_CACERT /etc/ssl/certs/cacert.pem
    TLS_REQCERT demand
  3. Ensure working:
    ldapsearch -x
  4. Have a look at server log file, the communication must go through port 636 now
    ldap1 slapd[2462]: conn=1005 fd=15 ACCEPT from IP= (IP=
    ldap1 slapd[2462]: conn=1005 fd=15 TLS established tls_ssf=128 ssf=128
    ldap1 slapd[2462]: conn=1005 op=0 BIND dn="" method=128
    ldap1 slapd[2462]: conn=1005 op=0 RESULT tag=97 err=0 text=
    ldap1 slapd[2462]: conn=1005 op=1 SRCH base="dc=dev,dc=local" scope=2 deref=0 filter="(objectClass=*)"
    ldap1 slapd[2462]: conn=1005 op=1 SEARCH RESULT tag=101 err=0 nentries=6 text=
    ldap1 slapd[2462]: conn=1005 op=2 UNBIND
    ldap1 slapd[2462]: conn=1005 fd=15 closed

How to create Certificates using OpenSSL

In order to create a new certificate you basically need to follow two steps: (a) create certificate request, (b) sign request by certificate authority. Since for step (b) you need certificate authority please have a look at previous post that details it.

Certificate Request

The process of creating a certificate request is the same as for certificate authority, except it is important to set valid Common Name that should be a FQDN (e.g. for the server that this request it for (the name that the client will access your host remotely).
ldap1:~/ca# openssl req -new -nodes -keyout newreq.pem -out newreq.pem
Generating a 2048 bit RSA private key
writing new private key to 'newreq.pem'
Country Name (2 letter code) [UA]:
State or Province Name (full name) [LV]:
Locality Name (eg, city) []:Lviv
Organization Name (eg, company) [XYZ Co]:
Organizational Unit Name (eg, section) []:
Common Name (eg, YOUR name) []
Email Address []:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

Sign Request

Here we are going to sign the client certificate request by our certificate authority:
ldap1:~/ca# /usr/lib/ssl/misc/ -sign
Using configuration from /usr/lib/ssl/openssl.cnf
Enter pass phrase for ./demoCA/private/cakey.pem: *******
Check that the request matches the signature
Signature ok
Certificate Details:
Certificate is to be certified until XXX (365 days)
Sign the certificate? [y/n]:y

1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated
Signed certificate is in newcert.pem
There are two important files we created: newreq.pem and newcert.pem. Consider rename those file to match the service they are created for, e.g. ldap1-key.pem and ldap1-cert.pem. You can combine them into a single file:
cat newreq.pem newcert.pem > new.pem

How to create Certificate Authority using OpenSSL

The Certificate Authority (CA) is used to verify the authenticity of a certificate. Start by installing openssl package:
apt-get install openssl

Create Private Certificate Authority

  1. OpenSSL (version 0.9.8) is installed to path /usr/lib/ssl. The script is not in search path, we are going to add it for just current session.
    export PATH=$PATH:/usr/lib/ssl/misc
  2. Let customize a bit configuration file (/usr/lib/ssl/openssl.cnf) that is used for certificate creation, but first make a backup copy. Make the following changes:
    [ req ]
    default_bits    = 2048
    [ req_distinguished_name ]
    countryName_default             = UA
    stateOrProvinceName_default     = LV
    0.organizationName_default      = XYZ Co
  3. Create a directory for all certificates (it can be any directory, we will create in home):
    mkdir ~/ca && cd ~/ca
  4. Answer few questions (hit enter to create a new when prompted for CA filename):
    ldap1:~/ca# -newca
    CA certificate filename (or enter to create)
    Making CA certificate ...
    Generating a 2048 bit RSA private key
    writing new private key to './demoCA/private/./cakey.pem'
    Enter PEM pass phrase: **************
    Verifying - Enter PEM pass phrase: **************
    Country Name (2 letter code) [UA]:
    State or Province Name (full name) [LV]:
    Locality Name (eg, city) []:Lviv
    Organization Name (eg, company) [XYZ Co]:
    Organizational Unit Name (eg, section) []:
    Common Name (eg, YOUR name) []:XYZ Root CA
    Email Address []:
    Please enter the following 'extra' attributes
    to be sent with your certificate request
    A challenge password []:
    An optional company name []:
    Using configuration from /usr/lib/ssl/openssl.cnf
    Enter pass phrase for ./demoCA/private/./cakey.pem: *****
    Check that the request matches the signature
    Signature ok
    Certificate Details:
    Write out database with 1 new entries
    Data Base Updated
  5. Secure Certificate Authority:
    chmod -R go-rwx ~/ca
Your Certificate Authority file is cacert.pem (it is located in ~/ca/demoCA directory).

Thursday, December 23, 2010

How to create a new user in OpenLDAP

We are going create a new account for John Smith. Here are few simple steps:
  1. We need create a template for a new user account jsmith (file add-user.ldif):
    # User primary group
    dn: cn=jsmith,ou=groups,dc=dev,dc=local
    cn: jsmith
    objectClass: top
    objectClass: posixGroup
    gidNumber: 10000
    # User account
    dn: uid=jsmith,ou=people,dc=dev,dc=local
    cn: John Smith
    givenName: John
    sn: Smith
    uid: jsmith
    uidNumber: 10000
    gidNumber: 10000
    homeDirectory: /home/jsmith
    mail: jsmith@dev.local
    objectClass: top
    objectClass: posixAccount
    objectClass: shadowAccount
    objectClass: inetOrgPerson
    objectClass: organizationalPerson
    objectClass: person
    loginShell: /bin/bash
    userPassword: {CRYPT}*
  2. Load user to ldap:
    ldapadd -cxWD cn=admin,dc=dev,dc=local -f add-user.ldif
    or if you are authenticated by Kerberos:
    ldapadd -f add-user.ldif
  3. Try to find it:
    ldapsearch -x uid=jsmith
  4. Set user password (consider store user password in kerberos instead):
    ldappasswd -xWD cn=admin,dc=dev,dc=local -S uid=jsmith,ou=people,dc=dev,dc=local
Read more about openldap here.

Debian OpenLDAP

OpenLDAP is a free, open source implementation of the Lightweight Directory Access Protocol (LDAP).

Install OpenLDAP Server

  1. Ensure the host name is FQDN:
    ldap1:~# hostname
    If it is not, issue the following:
    echo "" > /etc/hostname
    hostname -F /etc/hostname
  2. Install necessary packages (during a package configuration phase set admin password and accept all default options):
    apt-get -y install rsyslog slapd ldap-utils
  3. Setup system-wide defaults for LDAP clients (file /etc/ldap/ldap.conf):
    BASE    dc=dev,dc=local
    URI     ldap://
  4. Disable ipv6 support for slapd (file /etc/default/slapd):
    # Additional options to pass to slapd
    Restart slapd:
    /etc/init.d/slapd restart
    netstat -tunlp | grep slapd
    tcp        0      0   *               LISTEN      1557/slapd


  1. Create a file that enable ldap logging (file log-stats.ldif):
    # Enable LDAP logging
    dn: cn=config
    changetype: modify
    replace: olcLogLevel
    olcLogLevel: stats
  2. ... disable ldap logging (file log-none.ldif):
    # Disable LDAP logging
    dn: cn=config
    changetype: modify
    replace: olcLogLevel
    olcLogLevel: none
  3. And here is a command (changes are applied immediately, no need to restart slapd):
    ldapmodify -QY EXTERNAL -H ldapi:/// -f log-stats.ldif

What to index

  1. Create indexes to match the actual filter terms used in search queries. Read more here. We are going to add the following indexes: uid, cn. So here is our index file (file db-index.ldif):
    dn: olcDatabase={1}hdb,cn=config
    changetype: modify
    add: olcDbIndex
    olcDbIndex: uid eq
    add: olcDbIndex
    olcDbIndex: cn eq
    add: olcDbIndex
    olcDbIndex: ou eq
    add: olcDbIndex
    olcDbIndex: dc eq
    add: olcDbIndex
    olcDbIndex: uniqueMember eq
    add: olcDbIndex
    olcDbIndex: uidNumber eq
    add: olcDbIndex
    olcDbIndex: gidNumber eq
    Apply changes:
    ldapmodify -QY EXTERNAL -H ldapi:/// -f db-index.ldif

Reindex database

  1. Here is a simple script to reindex database (file /usr/local/sbin/slap-reindex). You do not need to run it often, that is depends how big is your database and how many changes occur, consider run it monthly:
    /etc/init.d/slapd stop > /dev/null
    su openldap -c "slapindex"
    /etc/init.d/slapd start > /dev/null

Simple tree structure

  1. Here is our simple structure:
  2. It correspond to the following (file init-tree.ldif):
    dn: ou=people,dc=dev,dc=local
    ou: people
    objectClass: organizationalUnit
    dn: ou=groups,dc=dev,dc=local
    ou: groups
    objectClass: organizationalUnit
  3. Add it to ldap:
    ldapadd -cxWD cn=admin,dc=dev,dc=local -f init-tree.ldif
  4. Test if we can find it:
    ldapsearch -x ou=people
    Here is search result:
    # extended LDIF
    # LDAPv3
    # base  (default) with scope subtree
    # filter: ou=people
    # requesting: ALL
    # people, dev.local
    dn: ou=people,dc=dev,dc=local
    ou: people
    objectClass: organizationalUnit
    # search result
    search: 2
    result: 0 Success
    # numResponses: 2
    # numEntries: 1

Wednesday, December 22, 2010

Debian Kerberos Slave

Slave KDCs provide an additional source of Kerberos ticket-granting services in the event of inaccessibility of the master KDC. It recommended that your KDCs have a predefined set of CNAME records (DNS hostname aliases), such as krb for the master KDC and kdc1, kdc2, ... for the slave KDCs. This way, if you need to swap a machine, you only need to change a DNS entry, rather than having to change hostnames.

Master (Primary) Kerberos Server

  1. Add a new slave ( to file /etc/krb5.conf (for the master and any other slaves):
            DEV.LOCAL = {
                    kdc =
                    kdc =
                    admin_server =
    Alternatively (preferred way) consider setup DNS discovery. Read here how.
  2. Add slave host principal:
    kadmin.local -q "addprinc -randkey host/"
    kadmin.local -q "ktadd host/"
  3. Create database propagation host list (file /etc/krb5kdc/kpropd.acl):
  4. Create a dump of the kerberos database (that is a default path for kprop utility):
    kdb5_util dump /var/lib/krb5kdc/slave_datatrans

Secondary (Slave, Read-Only) Kerberos Server

  1. Install Kerberos Server and xinetd (to be used for database propagation):
    apt-get install krb5-kdc xinetd
  2. Copy (a) realm configuration (file /etc/krb5.conf), (b) database propagation list (file /etc/krb5kdc/kpropd.acl), (c) keytab (file /etc/krb5.keytab), (d) logrotate settings from master, e.g. using ssh copy:
    scp kdc1:/etc/krb5.conf /etc
    scp kdc1:/etc/krb5kdc/kpropd.acl /etc/krb5kdc
    scp kdc1:/etc/krb5.keytab /etc
    scp kdc1:/etc/logrotate.d/krb5 /etc/logrotate.d
    mkdir /var/log/krb5
  3. Setup database propagation service (file /etc/xinetd.d/krb_prop):
    service krb_prop
            disable         = no
            socket_type     = stream
            protocol        = tcp
            user            = root
            wait            = no
            server          = /usr/sbin/kpropd
    Restart xinetd service:
    /etc/init.d/xinetd restart

Propagate database

  1. Propagate database from Master to Slave
    kdc1:~# kprop
    Database propagation to SUCCEEDED
  2. Create database stash key on slave
    kdb5_util stash
  3. Start Kerberos Slave service:
    /etc/init.d/krb5-kdc start

Automate database propagation

  1. Here is a script that populates master database to all slaves (run on master, file /usr/local/sbin/krb5-prop):
    /usr/sbin/kdb5_util dump /var/lib/krb5kdc/slave_datatrans
    if [ $error -ne 0 ]; then
      echo "Kerberos database dump failed."
      exit 1
    for slave in $slaves; do
      /usr/sbin/kprop $slave > /dev/null
      if [ $error -ne 0 ]; then
        echo "Kerberos propagation to host $slave failed."
    exit 0
    Ensure the file is executable:
    chmod +x /usr/local/sbin/krb5-prop
  2. Schedule a cron job (/usr/local/sbin/cron-krb5-prop):
    # Regular cron job for Kerberos database propagation
    # Every 53 minutes
    53 * * * * root test -x /usr/local/sbin/krb5-prop && krb5-prop >> $LOG
    .. and let cron know about it:
    ln -s /usr/local/sbin/cron-krb5-prop /etc/cron.d/cron-krb5-prop
Finally here is how to test it is working:
  1. Stop Master Kerberos server:
    /etc/init.d/krb5-kdc stop
  2. Open log file on Slave:
    tail -f /var/log/krb5/kdc.log
  3. Login to kerberos client:
    ssh user1@deby01
  4. Watch the log on Slave, you should see authentication messages.
Read more about kerberos here.

Tuesday, December 21, 2010

How to setup Kerberos DNS discovery

Kerberos DNS discovery can simplify the client hosts setup. The following need to be added to zone file.
$ORIGIN dev.local.
_kerberos-adm._tcp      SRV     0 0 749 kdc1
_kerberos               SRV     10 0 88
_kerberos               SRV     20 0 88
_kerberos-master        SRV     0 0 88
_kpasswd                SRV     0 0 464
The client configuration can now look like this (file /etc/krb5.conf):
        default_realm = DEV.LOCAL
# ...
        DEV.LOCAL = {

Let test this:
deby01:~$ host -t SRV _kerberos._udp has SRV record 10 0 88

Debian Kerberos Client

You must have Kerberos server running on the network, read here how to get it up. We are going to add host deby01 as a client for dev.local Kerberos realm.
  1. Ensure the host name is FQDN:
    ldap1:~# hostname -f
    If it is not, issue the following:
    echo "deby01" > /etc/hostname
    hostname -F /etc/hostname
  2. Install Kerberos client:
    apt-get -y install krb5-user libpam-krb5
  3. Configure client (file /etc/krb5.conf):
            default_realm = DEV.LOCAL
    # ...
            DEV.LOCAL = {
                    # The entry below can be commented 
                    # out in case there is dns 
                    # resolution for kdc
                    kdc =
                    admin_server =
  4. Add host principal:
    kadmin -p admin -q "addprinc -randkey host/"
    kadmin -p admin -q "ktadd host/"
Let verify it:
  1. List kerberos principals:
    deby01:~# kadmin -p admin -q "list_principals"
  2. List keys in keytab:
    klist -ke
  3. Now you can login to deby01 as user1.
  4. Have a look at log on kerberos server (file /var/log/krb5/kdc.log): krb5kdc[988](info): AS_REQ (4 etypes {18 17 16 23}) NEEDED_PREAUTH: user1@DEV.LOCAL for krbtgt/DEV.LOCAL@DEV.LOCAL, Additional pre-authentication required krb5kdc[988](info): AS_REQ (4 etypes {18 17 16 23}) ISSUE: authtime 1293635137, etypes {rep=18 tkt=18 ses=18}, user1@DEV.LOCAL for krbtgt/DEV.LOCAL@DEV.LOCAL krb5kdc[988](info): TGS_REQ (4 etypes {18 17 16 23}) ISSUE: authtime 1293635137, etypes {rep=18 tkt=18 ses=18}, user1@DEV.LOCAL for host/
The pam authentication by default is configured to authenticate user with kerberos with fallback to local authentication, that is fine so nothing need to be configured there.

How to add a new user to Kerberos

The Kerberos is used only for authentication purpose that means that user we are going to add must exists as a normal unix account (or ldap account).
root@kdc1:~# kadmin.local -q "addprinc user1"
Principal "user1@DEV.LOCAL" created.
Let test it out:
root@kdc1:~# kinit user1 && klist && kdestroy 
Default principal: user1@DEV.LOCAL
The operations must be performed on kdc1 that is Kerberos administrative server.

How to add a new host to Kerberos

Each host (a client computer) that need to be a part of kerberos realm must have principal and keytab. Let do that for host deby01. The command must be invoked on Kerberos administrative server (kdc1):
kadmin.local -q "addprinc -randkey host/"
This is run on client (deby01):
kadmin -p admin -q "ktadd host/"
or consider using the following script (file /usr/local/sbin/kdc-add):

if [ ! -z $1 ]; then type=$1; fi

sh -c "`cat /etc/hostname | xargs -t -I {} echo \
"kadmin -p admin -q \\\"addprinc -randkey $type/{}\\\""`"

sh -c "`cat /etc/hostname | xargs -t -I {} echo \
"kadmin -p admin -q \\\"ktadd $type/{}\\\""`"
You can run it on a machine you wish to add (you will be prompted to enter password two times):
Please note that each host added to kerberos must have fully qualified hostname. Both forward and reverse mapping must work properly. Here are few simple tests:
deby01:~# hostname

deby01:~# dig +short

deby01:~# dig -x +short
Read more here.

Debian Kerberos Master

Kerberos is a network authentication protocol. The idea is to be a secure, single sign-on authentication provider.
  1. Install Kerberos Server.
    apt-get -y install rsyslog krb5-{admin-server,user,doc}
  2. Create realm (this may take a long time, up to few minutes).
  3. Activate Kerberos administration by authorizing admin access (file /etc/krb5kdc/kadm5.acl).
    # ...
    */admin *
    admin *
  4. Setup logging (new file /etc/logrotate.d/krb5):
    /var/log/krb5/kadmin.log /var/log/krb5/kdc.log {
            rotate 7
    Create log directory
    mkdir /var/log/krb5
  5. Realm Configuration (file /etc/krb5.conf). In our case the kerberos server name is kdc1 and there is alias to it krb (used for administration purpose).
            default_realm = DEV.LOCAL
            DEV.LOCAL = {
                    kdc =
                    # kdc =
                    admin_server =
            .dev.local = DEV.LOCAL
            dev.local = DEV.LOCAL
            kdc = FILE:/var/log/krb5/kdc.log
            admin_server = FILE:/var/log/krb5/kadmin.log
  6. Restart kerberos services.
    invoke-rc.d krb5-admin-server restart ; \
    invoke-rc.d krb5-kdc restart
  7. Open another console and have a look at log files.
    cd /var/log/krb5/ ; \
    tail -f kadmin.log kdc.log
  8. Ensure services are running.
    root@kdc1:~# netstat -tunlp
    Active Internet connections (only servers)
    Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
    tcp        0      0   *               LISTEN      840/kadmind     
    tcp        0      0   *               LISTEN      840/kadmind     
    tcp6       0      0 :::464                  :::*                    LISTEN      840/kadmind     
    udp        0      0   *                           840/kadmind     
    udp        0      0    *                           861/krb5kdc     
    udp        0      0   *                           861/krb5kdc     
So far we have the services up and running, however in order to administer it we need create an administrative account:
  1. Add admin principal:
    kadmin.local -q "addprinc admin"
  2. Add host (kdc1) principal:
    kadmin.local -q "addprinc -randkey host/"
    kadmin.local -q "ktadd host/"
Now let test it:
root@kdc1:~# kinit admin && klist && kdestroy 
Password for admin@DEV.LOCAL: 
Ticket cache: FILE:/tmp/krb5cc_0
Default principal: admin@DEV.LOCAL

Valid starting     Expires            Service principal
12/21/10 18:05:14  12/22/10 04:05:14  krbtgt/DEV.LOCAL@DEV.LOCAL
 renew until 12/22/10 18:05:11
Read more here.