Setting up an OpenLDAP server on CentOS 7 and deploying NFS to export users’ home directories.
Software
Software used in this article:
- CentOS 7
- OpenLDAP 2.4.40
- nfs-utils 1.3.0
OpenLDAP Setup
Our OpenLDAP server resides on a 10.8.8.0/24 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".crt "$DOMAIN".key "$DOMAIN".pem # chgrp ldap "$DOMAIN".crt "$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://0.0.0.0:389/ ldaps://0.0.0.0:636/"
Enable and start the service:
# systemctl enable slapd.service # systemctl start slapd.service
Configure firewall:
# iptables -A INPUT -s 10.8.8.0/24 -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 # chmod 0600 /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 /root/ldifconfigs/ && cd /root/ldifconfigs/
Generate a userPassword value for the LDAP admin account:
# slappasswd -h {SSHA} New password: Re-enter new password: {SSHA}qFEhyuvWKiLGtOISbhbRlSijlMQGCAGh
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:
- The admin account (rootDN) has complete access,
- The autobind account can read-only,
- Anonymous users are provided access to the userPassword attribute for the initial connection to occur,
- 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/startssl.ca.crt - 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 EOF
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 userPassword: EOF
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 lisenet.com with a couple of organisational units for users and groups.
# cat > ./lisenet.com.ldif << EOF dn: dc=lisenet.com,dc=top o: lisenet.com dc: lisenet.com objectClass: dcObject objectClass: organization dn: ou=Users,dc=lisenet.com,dc=top objectClass: organizationalUnit ou: Users dn: ou=Groups,dc=lisenet.com,dc=top objectClass: organizationalUnit ou: Groups EOF
Apply changes:
# ldapadd -x -D cn=admin,dc=top -W -f ./lisenet.com.ldif
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=lisenet.com,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=lisenet.com,dc=top gidNumber: 5001 objectClass: top objectClass: posixGroup cn: alice dn: uid=vincent,ou=Users,dc=lisenet.com,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=lisenet.com,dc=top gidNumber: 5002 objectClass: top objectClass: posixGroup cn: vincent EOF
Apply:
# 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=lisenet.com,dc=top # ldappasswd -x -D cn=admin,dc=top -W -S uid=vincent,ou=users,dc=lisenet.com,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 10.8.8.0/24 -p tcp -m multiport --dport 111,2049,20048 -j ACCEPT # iptables -A INPUT -s 10.8.8.0/24 -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 /home/guests 10.8.8.0/24(rw,sync,no_subtree_check,root_squash)
# exportfs -rav exporting 10.8.8.0/24:/home/guests
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 10.8.8.2 is the NFS server’s IP):
# cat /etc/auto.guests * -rw 10.8.8.2:/home/guests/&
You made a pretty detailed guide!, nice work.
Unfortunately, I’m trying this in Centos 7 and I’m getting into errors with command ldapadd -Y EXTERNAL -H ldapi:/// -f ./initial_config.ldif
It shows this error:
SASL/EXTERNAL authentication started
SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
SASL SSF: 0
modifying entry “cn=config”
modifying entry “olcDatabase={1}monitor,cn=config”
ldap_modify: Other (e.g., implementation specific) error (80)
additional info: handler exited with 1
Has anyone else had this situation?, cheers.
Thanks for your feedback Javier. The command works for me on CentOS 7.3 with openldap-2.4.40-13:
Please make sure that you create the file
initial_config.ldif
as per instructions provided.I found the error!,
By mistake I didnt import the schemas properly, after this all worked well:
# 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
Thanks!!
Well done, I’m glad your fixed it!
I’m now having a hard time getting Samba on a different server (Centos 7 too) to use this LDAP to authenticate the samba users.
Do you have any howto for this?
Nothing published on this blog I’m afraid. It’s a tricky setup because Samba relies on the host OS and therefore needs uid/gid for a user, which makes it challenging to integrate with LDAP. Good luck!
Hi,
Thanks for the detailed instructions.. Very helpful..
where does the startssl.ca.crt come from ?
Thanks..
From StartCom CA (it stopped issuing digital certificates as of January 1, 2018). I’ve switched to Let’s Encrypt.
Hi thanks for the guide, is there anything specific you neede to change to use Let’s Encrypt?
You’re welcome! There isn’t anything specific you need to change to get LE working. In reality, you can use any CA that you want.
How to configure Samba using this LDAP configuration ?
This solution might help: https://access.redhat.com/solutions/53839
Hi Tomas,
Just wondering where / how do you get startssl.ca.crt in initial_config.ldif? And does olcPasswordHash has to be the same as olcRootPW?
I am running Cento 7.7 (openldap 2.4.44-21) and had to split each section in initial_config.ldif into separate files as it did was erroring out when it was all in one file.
Hey Marcin, StartSSL was a CA based in China that used provided free SSL certificates. There was no Let’s Encrypt back then.
If you need a free certificate for your LDAP server, use Let’s Encrypt.
I’m not sure if they have to be the same, but my understanding is that you should use the hashing algorithm that you define in
olcPasswordHash
. If you configure SSHA, then yourolcRootPW
password should be in a SSHA form.Thanks for the answers Tomas.
And thank you for awesome guide.