Setting up an OpenLDAP Server with SSL + NFS for User Home Directories on CentOS 7

Setting up an OpenLDAP server on CentOS 7 and deploying NFS to export users’ home directories.


Software used in this article:

  1. CentOS 7.2
  2. OpenLDAP 2.4.40
  3. nfs-utils 1.3.0

OpenLDAP Setup

Our OpenLDAP server resides on a local area network.

Installation and SSL Configuration

# yum install -y openldap-servers openldap-clients

Generate an RSA private key with a certificate sign request.

# cd /etc/pki/tls/private
# DOMAIN=ldap
# openssl genrsa -out "$DOMAIN".key 2048 && chmod 0600 "$DOMAIN".key
# openssl req -new -sha256 -key "$DOMAIN".key -out "$DOMAIN".csr

Now we can get some CA to sign our CSR, or we can sign it ourselves:

# openssl x509 -req -days 1825 -sha256 -in "$DOMAIN".csr -signkey "$DOMAIN".key \
  -out "$DOMAIN".crt

Convert PKCS#1 to PKCS#8:

# openssl pkcs8 -topk8 -inform pem -in "$DOMAIN".key \
  -outform pem -nocrypt -out "$DOMAIN".pem

Ensure the private keys can be read by the ldap group:

# chmod 640 "$DOMAIN".key "$DOMAIN".pem
# chgrp ldap "$DOMAIN".key "$DOMAIN".pem
# mv "$DOMAIN".crt ../certs/

Open /etc/sysconfig/slapd for editing and put the following to enable LDAPS:

SLAPD_URLS="ldapi:/// ldap:// ldaps://"

Enable and start the service:

# systemctl enable slapd.service
# systemctl start slapd.service

Configure firewall:

# iptables -A INPUT -s -p tcp -m multiport --dport 389,636 -j ACCEPT

Import Basic OpenLDAP Schemas and Create a DB

Quite a few LDAP schemas are available, import as required.

# ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/cosine.ldif
# ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/nis.ldif
# ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/inetorgperson.ldif

Although only root can run slapadd, the slapd service runs as the ldap user. Because of this, the directory server is unable to modify any files created by slapadd.

# cp /usr/share/openldap-servers/DB_CONFIG.example /var/lib/ldap/DB_CONFIG
# chown -R ldap:ldap /var/lib/ldap/
# slaptest

Configure OpenLDAP

We’ll need a directory to store temp config files:

# mkdir /tmp/ldifconfigs/
# cd /tmp/ldifconfigs/

Generate a userPassword value for the LDAP admin account:

# slappasswd -h {SSHA}
New password:
Re-enter new password:

Our initial LDAP configuration file initial_config.ldif can be seen below .

We enable all logging, set password hash to SSHA (rather than SHA), provide paths to SSL certificates and keys, put a high cipher suite to be used.

The RootDN entry is the Distinguished Name (DN) for a user who is unrestricted by access controls or administrative limit parameters set for operations on the LDAP directory. We use cn=admin,dc=top for it. Note that our suffix is set to dc=top as we intend to use multiple domains under the tree (top domain component).

We also define a guest account cn=autobind,dc=top for read-only access. This is mainly to bind to the LDAP server when anonymous binding is not allowed, for services like nslcd.

Then there is an access control list which determines who can authenticate against the OpenLDAP server:

  1. The admin account (rootDN) has complete access,
  2. The autobind account can read-only,
  3. Anonymous users are provided access to the userPassword attribute for the initial connection to occur,
  4. All users have read access to their passwords due to “by self write” permissions.

Create the file.

# cat > ./initial_config.ldif << EOF
dn: cn=config
changetype: modify
replace: olcLogLevel
olcLogLevel: -1
replace: olcPasswordHash
olcPasswordHash: {SSHA}
replace: olcTLSCACertificateFile
olcTLSCACertificateFile: /etc/pki/tls/certs/
replace: olcTLSCertificateFile
olcTLSCertificateFile: /etc/pki/tls/certs/ldap.crt
replace: olcTLSCertificateKeyFile
olcTLSCertificateKeyFile: /etc/pki/tls/private/ldap.pem
replace: olcTLSCipherSuite
olcTLSCipherSuite: HIGH
replace: olcTLSVerifyClient
olcTLSVerifyClient: never

dn: olcDatabase={1}monitor,cn=config
changetype: modify
replace: olcAccess
olcAccess: {0}to * by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" read by dn.base="cn=admin,dc=top" read by * none

dn: olcDatabase={2}hdb,cn=config
changetype: modify
replace: olcSuffix
olcSuffix: dc=top
replace: olcRootDN
olcRootDN: cn=admin,dc=top
replace: olcRootPW
olcRootPW: {SSHA}qFEhyuvWKiLGtOISbhbRlSijlMQGCAGh
replace: olcLastMod
olcLastMod: TRUE
replace: olcDbCheckpoint
olcDbCheckpoint: 512 30
replace: olcAccess
olcAccess: {0}to attrs=userPassword,shadowLastChange by dn="cn=admin,dc=top" write by dn="cn=autobind,dc=top" read by self write by anonymous auth by * none
olcAccess: {1}to dn.base="" by * read
olcAccess: {2}to * by dn="cn=admin,dc=top" write by dn="cn=autobind,dc=top" read by self write by users read by anonymous auth by * none

Apply configuration form the file:

# ldapadd -Y EXTERNAL -H ldapi:/// -f ./initial_config.ldif

Create a base configuration file. This defines the top domain component dc=top as well as the admin and the autobind users.

# cat > ./base.ldif << EOF
dn: dc=top
objectClass: top
objectClass: dcObject
objectclass: organization
o: top
dc: top

dn: cn=admin,dc=top
objectClass: simpleSecurityObject
objectclass: organizationalRole
description: LDAP Admin Access
userPassword: {SSHA}qFEhyuvWKiLGtOISbhbRlSijlMQGC315

dn: cn=autobind,dc=top
objectClass: simpleSecurityObject
objectclass: organizationalRole
description: LDAP Read-only Access

Apply changes, and then create a password for the autobind account (we left the userPassword field blank intentionally).

# ldapadd -x -D cn=admin,dc=top -W -f ./base.ldif
# ldappasswd -x -D cn=admin,dc=top -W -S cn=autobind,dc=top

We are now going to create a domain called with a couple of organisational units for users and groups.

# cat > ./ << EOF 
objectClass: dcObject
objectClass: organization

dn: ou=Users,,dc=top
objectClass: organizationalUnit
ou: Users

dn: ou=Groups,,dc=top
objectClass: organizationalUnit
ou: Groups

Apply changes:

# ldapadd -x -D cn=admin,dc=top -W -f ./

As we have a domain created, we can add some users. For those who already have multiple local user accounts created on a system, it would be wise to use the MigrationTools utility.

The MigrationTools are a set of Perl scripts for migrating users, groups, aliases, hosts, netgroups, networks and services from existing nameservices (flat files, NIS, and NetInfo) to LDAP.

We’re going to create two LDAP users, alice and vincent, together with their respective groups. Home directories (/home/guests/) will be exported via NFS. Note the shadowLastChange value.

We need objectClass: person to assign surnames, objectClass: inetOrgPerson for mail and given name, plus objectClass: posixAccount to set up user’s password.

# cat > ./users.ldif << EOF 
dn: uid=alice,ou=Users,,dc=top
uid: alice
uidNumber: 5001
gidNumber: 5001
objectClass: top
objectClass: person
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
userPassword: {SSHA}biYSGrLyQG/+ntABuIYF2rXyzDgZdBaU
cn: Alice Abernathy
gn: Alice
sn: Abernathy
mail: [email protected]
shadowLastChange: 16890
shadowMin: 0
shadowMax: 99999
shadowWarning: 14
shadowInactive: 3
loginShell: /bin/bash
homeDirectory: /home/guests/alice

dn: cn=alice,ou=Groups,,dc=top
gidNumber: 5001
objectClass: top
objectClass: posixGroup
cn: alice

dn: uid=vincent,ou=Users,,dc=top
uid: vincent
uidNumber: 5002
gidNumber: 5002
objectClass: top
objectClass: person
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
userPassword: {SSHA}biYSGrLyQG/+ntABuIYF2rXyzDgZdBaU
cn: Vincent Valentine
gn: Vincent
sn: Valentine
mail: [email protected]
shadowLastChange: 16890
shadowMin: 0
shadowMax: 99999
shadowWarning: 14
shadowInactive: 3
loginShell: /bin/bash
homeDirectory: /home/guests/vincent

dn: cn=vincent,ou=Groups,,dc=top
gidNumber: 5002
objectClass: top
objectClass: posixGroup
cn: vincent


# ldapadd -x -D cn=admin,dc=top -W -f ./users.ldif

In case we want to change the pre-defined passwords, we can do so by issuing the following:

# ldappasswd -x -D cn=admin,dc=top -W -S uid=alice,ou=users,,dc=top
# ldappasswd -x -D cn=admin,dc=top -W -S uid=vincent,ou=users,,dc=top

Here’s how out LDAP structure should look like:

More domains and users can be easily added under the top domain component.

NFS Setup

Package Installation and Firewall

Install nfs utilities, enable and start services:

# yum install nfs-utils
# systemctl enable rpcbind && systemctl start rpcbind
# systemctl enable nfs-server && systemctl start nfs-server

Configure firewall for NFS (rpc-bind, nfs and mountd):

# iptables -A INPUT -s -p tcp -m multiport --dport 111,2049,20048 -j ACCEPT
# iptables -A INPUT -s -p udp -m multiport --dport 111,2049,20048 -j ACCEPT

Create Home Directories and Configure Exports

Create home directories for LDAP users alice and vincent. Note the user id and the group id numbers which we used earlier when initially creating users on LDAP.

# mkdir -m0750 -p /home/guests/{alice,vincent}
# chown 5001:5001 /home/guests/alice/
# chown 5002:5002 /home/guests/vincent/

Configure NFS exports:

# cat /etc/exports
# exportfs -rav

Check the “related posts” section for how to configure CentOS 7 to use LDAP authentication with NFS automount.

Automount configuration should look something like this (where is the NFS server’s IP):

# cat /etc/auto.guests
*  -rw

Related Posts

Setup LDAP Authentication on CentOS 7

Configure NFS Automount on CentOS 7

Leave a Reply

Your email address will not be published. Required fields are marked *