May 14, 2009

Centralized authentication with OpenLDAP

Setting up a Certificate Authority

On a separate server, preferably isolated from the network and physically secured, create the Certificate Authority that will generate all the certificates for TLS encryption:

[root@host]# yum install openssl openssl-devel
[root@host]# vi /etc/pki/tls/openssl.cnf
[root@host]# cd /etc/pki/tls/misc
[root@host]# ./CA -newca

note: The common name field must be the machine's hostname!

This process does the following:

1. Creates the directory /etc/pki/CA (by default), which contains files necessary for the operation of a certificate authority
2. Creates a public-private key pair for the CA in the file /etc/pki/CA/private/cakey.pem. The private key must be kept private in order to ensure the security of the certificates the CA will later sign.
3. Signs the public key (using the corresponding private key, in a process called self-signing) to create the CA certificate, which is then stored in /etc/pki/CA/cacert.pem.

Creating a certificate for the LDAP server

Change into the CA certificate directory.

[root@host]# cd /etc/pki/tls/certs

Generate a key pair for the LDAP server, ldapserverkey.pem is the private key.

[root@host]# openssl genrsa -out ldapserverkey.pem 2048

Generate a certificate signing request (CSR) for the CA to sign.

[root@host]# openssl req -new -key ldapserverkey.pem -out ldapserver.csr

Sign the ldapserver.csr request, which will produce the server certificate. It will ask for a password, it's the same as when the CA cerificate was created

[root@host]# openssl ca -in ldapserver.csr -out ldapservercert.pem

How TLS Communication Works

There is a sequence of events that occur prior to the creation of an LDAP communication session using TLS. These include the following steps:

1. Both the LDAP server and client need to be configured with a shared copy of a CA certificate beforehand.
2. When the TLS LDAP connection is made, the client and server negotiate their SSL encryption scheme.
3. The LDAP server then sends its public encryption key and its server certificate (the certificate contains the public key).
4. The LDAP client inspects the server certificate to make sure that it hasn't expired and takes note of the name and key ID of the CA server that issued it. It then checks this CA information with all the CA certificates in its database to determine whether the server certificate should be trusted.
5. If everything is valid, the LDAP client then creates a random "premaster" secret encryption key that it encrypts with the LDAP server's public key. It then sends the encrypted encryption key to the LDAP server.
6. When public keys are created, a special "private" key is also simultaneously created. Anything encrypted with the public key can only be decrypted with the private key and vice versa. The server then uses its private key to extract the premaster key.
7. The client and server then use the premaster key to generate a master secret that will be the same for both, but will never be transmitted so that a third-party cannot intercept it.
8. The master secret key is then used to create session keys that will be used to encrypt all future communication between client and server for the duration of the TLS session.

Installing the Certificate on the LDAP Server

Create the PKI directory for LDAP certificates if it does not already exist

[root@host]# mkdir /etc/pki/tls/ldap
[root@host]# chown root:root /etc/pki/tls/ldap
[root@host]# chmod 755 /etc/pki/tls/ldap

Copy the private key and the certificate from the CA server

[root@host]# scp -r caserver:/etc/pki/tls/certs/ldapserverkey.pem /etc/pki/tls/ldap/serverkey.pem
[root@host]# scp -r caserver:/etc/pki/tls/certs/ldapservercert.pem /etc/pki/tls/ldap/servercert.pem

Verify the ownership and permissions of these files

[root@host]# chown root:ldap /etc/pki/tls/ldap/serverkey.pem
[root@host]# chown root:ldap /etc/pki/tls/ldap/servercert.pem
[root@host]# chmod 640 /etc/pki/tls/ldap/serverkey.pem
[root@host]# chmod 640 /etc/pki/tls/ldap/servercert.pem

Copy the CA's public certificate from the CA server residing in /etc/pki/CA/cacert.pem to the LDAP server

[root@host]# mkdir /etc/pki/tls/CA
[root@host]# scp -r caserver:/etc/pki/CA/cacert.pem /etc/pki/tls/CA/
[root@host]# chown root:root /etc/pki/tls/CA/cacert.pem
[root@host]# chmod 644 /etc/pki/tls/CA/cacert.pem

To test the TLS connectivity run

[root@host]# openssl s_client -connect cybervirt1:636 -showcerts

Installing CA's public certificate from the CA server residing in /etc/pki/CA/cacert.pem to the LDAP clients

On all clients run

[root@host]# scp -r caserver:/etc/pki/CA/cacert.pem /etc/pki/tls/CA/

Installing OpenLDAP

You can either download OpenLDAP source and compile it after you install BerkeleyDB

[root@host]# cd /usr/src
[root@host]# wget
[root@host]# cd /usr/src/db-4.7.25/build_unix
[root@host]# ../dist/configure
[root@host]# make; make install
[root@host]# cd /usr/src
[root@host]# wget
[root@host]# tar zxfv openldap-stable-20080813.tgz
[root@host]# cd openldap-2.4.11
[root@host]# CPPFLAGS="-I/usr/local/BerkeleyDB.4.7/include"
[root@host]# export CPPFLAGS
[root@host]# LDFLAGS="-L/usr/local/lib -L/usr/local/BerkeleyDB.4.7/lib -R/usr/local/BerkeleyDB.4.7/lib"
[root@host]# export LDFLAGS
[root@host]# LD_LIBRARY_PATH="/usr/local/BerkeleyDB.4.7/lib"
[root@host]# export LD_LIBRARY_PATH
[root@host]# ./configure;make;make intstall

Or you can install it with yum

[root@host]# yum install -y openldap openldap-devel openldap-servers openldap-clients

Starting OpenLDAP server

For different versions of ldap (from source or rpm) make sure /usr/local/etc/openldap/ldap.conf is the same as /etc/openldap/ldap.conf or there will be CA error.

[root@host]# /usr/local/libexec/slapd -f /usr/local/etc/openldap/slapd.conf -d255 -h 'ldap:/// ldaps:///'

Migrating all user accounts in to OpenLDAP

Install the perl migration tool and migrate all files (passwd, groups, network, etc) by change the domain in the file bellow to

[root@host]# wget
[root@host]# tar zxfv MigrationTools.tgz
[root@host]# vi /usr/share/openldap/migration/
[root@host]# /usr/share/openldap/migration/

Changing the authentication method

Two files need to be changed for an ssh client to authenticate to OpenLDAP - /etc/pam.d/system-auth-ac and /etc/nsswitch. You can do that manually or by running authconfig

[root@host]# authconfig --disableldap --enableldapauth --ldapbasedn="dc=planetdiscover,dc=com" --disableldaptls --update
[root@host]# vi /etc/pam.d/system-auth-ac

auth required
auth sufficient nullok try_first_pass
auth requisite uid >= 500 quiet
auth sufficient use_first_pass
auth required

account required broken_shadow
account sufficient uid < 500 quiet
account [default=bad success=ok user_unknown=ignore]
account required

password requisite try_first_pass retry=3
password sufficient md5 shadow nullok try_first_pass use_authtok
password sufficient use_authtok
password required

session optional revoke
session required
session [success=1 default=ignore] service in crond quiet use_uid
session required
session optional

session optional /lib/security/$ISA/

[root@host]# vi /etc/nsswitch

passwd: files ldap
shadow: files ldap
group: files ldap
automount: files ldap

Configuring OpenLDAP server and clients

Here's how /etc/openldap/slapd.conf and /usr/local/etc/openldap/slapd.conf server config files should look like

include /usr/local/etc/openldap/schema/core.schema
include /usr/local/etc/openldap/schema/cosine.schema
include /usr/local/etc/openldap/schema/inetorgperson.schema
include /usr/local/etc/openldap/schema/nis.schema
pidfile /usr/local/var/run/
argsfile /usr/local/var/run/slapd.args
access to attr=userPassword
by anonymous auth
by self write
by * none
access to attrs=shadowLastChange
by self write
by * read
access to * by * read
database bdb
suffix "dc=planetdiscover,dc=com"
rootdn "cn=Manager,dc=planetdiscover,dc=com"
rootpw {MD5}Tw4es8U1dRL2oLhM58ZBhA==
directory /usr/local/var/openldap-data
index objectClass eq
TLSCACertificateFile /etc/pki/tls/CA/cacert.pem
TLSCertificateFile /etc/pki/tls/ldap/servercert.pem
TLSCertificateKeyFile /etc/pki/tls/ldap/serverkey.pem
security simple_bind=128
loglevel stats2

The client config file in /etc/ldap.conf

base dc=planetdiscover,dc=com
uri ldap://
timelimit 120
bind_timelimit 120
idle_timelimit 3600
nss_initgroups_ignoreusers root,ldap,named,avahi,haldaemon,dbus,radvd,tomcat,radiusd,news,mailman
pam_password md5
ssl start_tls
tls_checkpeer yes
tls_cacertdir /etc/pki/tls/CA
tls_cacertfile /etc/pki/tls/CA/cacert.pem

The /etc/openldap/ldap.conf and /usr/local/etc/openldap/ldap.conf client config files

BASE dc=planetdiscover, dc=com
URI ldap://
TLS_CACERTDIR /etc/pki/tls/CA
TLS_CACERT /etc/pki/tls/CA/cacert.pem

Various OpenLDAP operations and examples

### Define the top-level organization unit ###

## Build the root node.
dn: dc=planetdiscover,dc=com
dc: planetdiscover
objectClass: dcObject
objectClass: organizationalUnit
ou: planetdiscover Dot Org

## Build the people ou container.
dn: ou=people,dc=planetdiscover,dc=com
ou: people
objectClass: organizationalUnit

## Build the group ou container.
dn: ou=group,dc=planetdiscover,dc=com
ou: group
objectclass: organizationalUnit

## Add the records offline
[root@host]# slapadd -v -l /tmp/top.ldif

## Add a user LDIF entry for Jerry Carter. cn is the mandatory attribute for this objectclass

dn: cn=Jerry Carter,ou=people,dc=planetdiscover,dc=com
cn: Jerry Carter
sn: Carter
This e-mail address is being protected from spambots. You need JavaScript enabled to view it

telephoneNumber: 555-123-1234
objectclass: inetOrgPerson

## Add a user LDIF entry for root. uid is the mandatory attribute in this case

dn: uid=root,ou=People,dc=planetdiscover,dc=com
uid: root
cn: root
objectClass: account
objectClass: posixAccount
objectClass: top
objectClass: shadowAccount
userPassword: {crypt}$1$Kp8hx.m0$Y1Aw37IStTqU8UU5kLgbq.
shadowLastChange: 13692
shadowMax: 99999
shadowWarning: 7
loginShell: /bin/bash
uidNumber: 0
gidNumber: 0
homeDirectory: /root
gecos: root

[root@host]# ldapmodify -D "cn=Manager,dc=planetdiscover,dc=com" -w secret -x -a -f /tmp/users.ldif

## Modify. Add a web page location to Jerry Carter.
dn: cn=Jerry Carter,ou=people,dc=planetdiscover,dc=com
changetype: modify
add: labeledURI

## Modify. Remove an email address from Gerald W. Carter.
dn: cn=Gerald W. Carter,ou=people,dc=planetdiscover,dc=com
changetype: modify
delete: mail
This e-mail address is being protected from spambots. You need JavaScript enabled to view it

## Modify. Remove the entire entry for Peabody Soup.
dn: cn=Peabody Soup,ou=people,dc=planetdiscover,dc=com
changetype: delete

[root@host]# ldapmodify -D "cn=Manager,dc=planetdiscover,dc=com" -w secret -x -v -f /tmp/update.ldif

## Delete dn root.
[root@host]# ldapdelete -D "cn=Manager,dc=planetdiscover,dc=com" -w secret -x -r -v "uid=root,ou=People,dc=planetdiscover,dc=com"

## Delete the entire dn ou=people subtree.
[root@host]# ldapdelete -D "cn=Manager,dc=planetdiscover,dc=com" -w secret -x -r -v "ou=people,dc=planetdiscover,dc=com"

## Search for uid cybergod record
[root@host]# ldapsearch -x -b "dc=planetdiscover,dc=com" "(uid=cybergod)"
# -b can be omited it's from where to start the search
[root@host]# ldapsearch -x -W -D cn="Manager,dc=planetdiscover,dc=com" "(uid=cybergod)" -Z
# -Z is for Using TLS it goes with -W for the Manager password

## Search for all objectclass records
[root@host]# ldapsearch -x -b "dc=planetdiscover,dc=com" "(objectclass=*)"

## Search using SASL DIGEST-MD5
[root@host]# ldapsearch -U
This e-mail address is being protected from spambots. You need JavaScript enabled to view it
-b "dc=planetdiscover,dc=com" "(objectclass=*)" -Y DIGEST-MD5

## Changing users password to "test" online through TLS
[root@host]# ldappasswd -s test -x -W -D cn="Manager,dc=planetdiscover,dc=com" "uid=cybergod,ou=People,dc=planetdiscover,dc=com" -Z

## Show ldap information
[root@host]# ldapsearch -x -s base -b "" "(objectclass=*)" +
[root@host]# ldapsearch -h localhost -p 389 -x -b "" -s base -LLL supportedSASLMechanisms

## Generate ssha password to use in slapd.conf
[root@host]# slappasswd