Introduction
I recently built an ESX lab and wanted central authentication. I’m a linux guy, so AD would be of minimal utility. Instead, I decided to dedicate one of my spare PCs as DNS, DHCP, LDAP, and SysLog. I decided to conquer LDAP first. It turns out to be kind of tricky.
- The openldap packages will get the server up, but you wont’ have the necessary base to add users / groups.
- Another goal is automounted NFS home directories – the Centos6 RPMs don’t have the autofs.schema file that makes this possible.
- All of the docs you’ll read will talk about modifying slapd.conf; meanwhile, the latest versions of openldap have deprecated slapd.conf in favor of slapd.d.
At it’s core, I did the following:
- Install the openldap packages from centos repo
- Acquired the migrationtools to create the base.ldif
- The migrationtools are made by the same folks that make the nss-pam-ldap stuff, so I figured this was the best way to get a compliant directory structure.
- Acquired the autofs.schema file from the CentOS 5 repo, it has the necessary file.
- You’ll still need to build the necessary entries for autofs in the LDAP directory, I followed this guy’s guide.
- I used phpLDAPadmin to browse the directory and add entries manually.
- You’ll need to modify selinux to get this thing working right in apache.
- I’ve heard Apache Directory Studio is also pretty nice, but I haven’t checked it out.
Update 11/21: Trying to get a slave set up and I noticed that my config doesn’t allow you to interact with the cn=config DIT. Updated that section.
Let’s begin, shall we?
This document was converted from Confluence Markup. You may see residual formatting errors – I’m working through them as best I can.
Prep work: Generate a CA cert and a server cert.
Follow this guide, starting at step 1B to generate the CA cert. You’ll need to put this on the clients later.
Don’t put a passphrase on the server.key otherwise slapd will need it to encrypt things – the problem is that it won’t know how to ask.
If you did it right, you should have 5 files (although you don’t need the .csr after you have the .crt)
ldapdev.example.com.ca.crtldapdev.example.com.ca.keyldapdev.example.com.server.crtldapdev.example.com.server.csrldapdev.example.com.server.key
The *.ca.crt and *.ca.key are the certificate authority files. You’ll need the .crt on all your clients. The .key will be needed if you want to certify another server, so put that somewhere safe.
The *.server.crt and *.server.key belong in /etc/openldap/cacerts and are used to provide the encryption.
The server’s private key is sensitive data and must only be readable by the user that slapd runs as, so the permissions are explicitly restricted on the key file above. The cert files should be publically readable.
Get the daemon running without anything fancy in there
I used the OpenLDAP.org Admin Guide and the Quick Start Guide, with a little deviation. The quick start guide has you (still) modifying and configuring everything via slapd.conf. So, we’ll do what they tell us, then we’ll port the slapd.conf over to slapd.d using slaptest (later).
- Install the necessary rpms
yum install openldap-servers openldap-clients nss-pam-ldapd migrationtools
- openldap-servers contains the daemon and configs, almost everything you need to set up the service
- openldap-clients are the CLI utilities for interacting with the server. You’ll need these later when we’re setting up the directory structure and schemas.
- nss-pam-ldapd is the plugin that lets the local box call an LDAP box for auth. You don’t need this if you don’t want to use LDAP for client auth on the server.
- The MigrationTools is a set of perl scripts that help you turn local authentication setups into ldap setups.
- Acquire some extra files that we’ll need.
wget http://bay.uchicago.edu/centos/5/os/x86_64/CentOS/openldap-servers-2.3.43-25.el5.x86_64.rpm
- The openldap-servers-2.3.43-25.el5.x86_64.rpm contains two files we need.
- slapd.conf
- autofs.schema
- You can use
rpm2cpio ./openldap-servers-2.3.43*.rpm | cpio -idvto extract the rpm into a set of directories (without installing the rpm) - See TK [the child page] for these files if you can’t find them.
- The openldap-servers-2.3.43-25.el5.x86_64.rpm contains two files we need.
- Toss autofs.schema with the others in
/etc/openldap/schema/. - Now we’re ready to modify slapd.conf and get this party started. Here are the main things to change:
- Up at the top, add the autofs.schema in there with the other includes:
include /etc/openldap/schema/core.schema include /etc/openldap/schema/cosine.schema include /etc/openldap/schema/inetorgperson.schema include /etc/openldap/schema/nis.schema include /etc/openldap/schema/autofs.schema
- I don’t like that “allow bind_v2″ option. Couldn’t tell you why. Comment that nasty out.
# Allow LDAPv2 client connections. This is NOT the default. #allow bind_v2
- Lines 51-53 concern the TLS certs. I put the server key/cert in ldap’s home dir,
/var/lib/ldap, and modified the permissions toroot:ldap// 640. Then I put the ca-cert (world readable) in/etc/openldap/cacerts/.TLSCACertificateFile /etc/openldap/cacerts/ldapdev.example.com.ca.crt TLSCertificateFile /var/lib/ldap/ldapdev.example.com.server.crt TLSCertificateKeyFile /var/lib/ldap/ldapdev.example.com.server.key
- Lines 86-92 are the meat and potatoes of why we came in here.
database bdb suffix "dc=my-domain,dc=com" #suffix "dc=eng,dc=uni,dc=edu,dc=eu" rootdn "cn=Manager,dc=my-domain,dc=com" # Cleartext passwords, especially for the rootdn, should # be avoided. See slappasswd(8) and slapd.conf(5) for details. # Use of strong authentication encouraged. # rootpw secret # rootpw {crypt}sDIOPfJmmKGrt- The database line is good – bdb is the preferred backend.
- The suffix will need to change – the example is for my-domain.com. I added in an example showing eng.uni.edu.eu for reference.
- You’ll also need to edit the rootdn – manager is typical, as is admin. Just remember what you pick here, you’ll need it when you need to interact with the directory for some activities.
- You’ll need to set the rootpw. Use the slappasswd utility to generate something, then copy the output into slapd.conf for the rootpw.
[root@ldapdev ldaptest]# slappasswd New password: Re-enter new password: {SSHA}SiopjfmNDDnfmRjU3msFjKLzNxWEer3t
- If you want to be able to modify the config while the DB is online, which is the whole “feature” of the slapd.d config model, you need to add this above the first database definition – in our case, that’s line 85.
database config rootdn "cn=Manager,cn=config" rootpw secret
Set the rootpw here with slappasswd just as you did above.
- Up at the top, add the autofs.schema in there with the other includes:
- Slaptest will bark if there isn’t a
DB_CONFIGfile in/var/lib/ldap. Lets get that out of the way:cp /usr/share/openldap-servers/DB_CONFIG.example /var/lib/ldap/DB_CONFIG chown ldap:ldap /var/lib/ldap/DB_CONFIG chmod 600 /var/lib/ldap/DB_CONFIG vi /var/lib/ldap/DB_CONFIG #Delete all the comments in this file. It makes the resulting output tidier/easier to read/maintain later.
- Cool. The new config is ready, and our schemas are in place. Lets get the garbage that was installed by
yumout of the way.cp -av /etc/openldap /etc/openldap.orig cp -av /var/lib/ldap /var/lib/ldap.orig #This isn't necessary if you don't have an existing ldap configuration or if you've never started slapd. rm -rf /etc/openldap/slapd.d mkdir /etc/openldap/slapd.d && chown ldap:ldap /etc/openldap/slapd.d
- Now the juke – we run
slaptestto convert theslapd.confinto the newslapd.dformat. This is what success looks like:[root@ldapdev ldapinstall]# slaptest -f ./slapd.conf -F /etc/openldap/slapd.d/ bdb_db_open: database "dc=example,dc=com": db_open(/var/lib/ldap/id2entry.bdb) failed: No such file or directory (2). backend_startup_one (type=bdb, suffix="dc=example,dc=com"): bi_db_open failed! (2) slap_startup failed (test would succeed using the -u switch)
- The new directory will be owned by root, and that will gum things up. Change the ownership to ldap:ldap
chown -Rv ldap:ldap /var/lib/ldap /etc/openldap/slapd.d
- You may now start the daemon.
service slapd start
- You can verify that the service is running with ldapsearch. We don’t have much to search through so far, so lets just look at the namingContexts. Note that it comes back with dc=example,dc=com. If there’s nothing under the “dn:” line, or you have other errors, go back and see what you missed above.
[root@ldapdev2 ldapinstall]# ldapsearch -ZZ -x -b '' -s base '(objectclass=*)' namingContexts ## The -ZZ forces TLS. # extended LDIF # # LDAPv3 # base <> with scope baseObject # filter: (objectclass=*) # requesting: namingContexts # # dn: namingContexts: dc=example,dc=com # search result search: 2 result: 0 Success # numResponses: 2 # numEntries: 1
- Next we need to modify the ACLs to increase security. It doesn’t appear that slaptest will pull the ACLs from slapd.conf, so we set these by hand.
- Open up the database config object in the cn=config directory.
vi "/etc/openldap/slapd.d/cn=config/olcDatabase={1}bdb.ldif" - Add the following lines
olcAccess: to attrs=userPassword by self write by anonymous auth by dn="uid=proxyuser,ou=People,dc=example,dc=com" read by * none olcAccess: to attrs=shadowLastChange by self write by dn="uid=proxyuser,ou=People,dc=example,dc=com" read by * none olcAccess: to * by dn="uid=proxyuser,ou=People,dc=example,dc=com" read by * none
- This sets us up for using a “proxy user” to handle the LDAP reads. You wouldn’t want a rogue client to be able to perform full reads. If you don’t want to use the proxy user, change the following:
olcAccess: to attrs=userPassword by self write by anonymous auth by users read by * none olcAccess: to attrs=shadowLastChange by self write by users read by * none olcAccess: to * by * read
- I haven’t tested that config because it seems silly to me. I recommend consulting the Access Control section of the OpenLDAP Admin Guide, and checking your work by starting slapd in acl debug mode:/
slapd -d acl
- I haven’t tested that config because it seems silly to me. I recommend consulting the Access Control section of the OpenLDAP Admin Guide, and checking your work by starting slapd in acl debug mode:/
- This sets us up for using a “proxy user” to handle the LDAP reads. You wouldn’t want a rogue client to be able to perform full reads. If you don’t want to use the proxy user, change the following:
- Open up the database config object in the cn=config directory.
- Enable ACL level logging:
- Open up
/etc/openldap/slapd.d/cn=config.ldifand add the following line, right under the TLS definitions (lines 27-30):olcLoglevel: 128
- This enables logging at the slapd level, but we need to tell syslog to actual commit these entries to file. Open up
/etc/rsyslog.confand add this above the block o’ comments at the bottom:# Save slapd messages local4.* /var/log/slapd.log
- Open up
- Open up the local firewall for port 389:
-A INPUT -m state --state NEW,ESTABLISHED -m tcp -p tcp -s 192.168.2.0/24 --dport 389 -j ACCEPT
- If you don’t want to restrict the source IP range, omit the
-s 192.168.2.0/24portion.
- If you don’t want to restrict the source IP range, omit the
Next up: Creating a directory base that’s compliant with the nss-pam-ldapd / pam_ldap modules.
Creating the directory base
Technically, you can store all sorts of goofy stuff in an LDAP directory and configure access to different parts of it based on who is asking and how they’re authenticated. It’s meant to be flexible for use with many applications. However, most of us just want to use it to have centralized authentication of Linux users. A nice little bonus is being able to have your home directory on an nfs share, and have that directory automounted anywhere you login. Right now, lets focus on creating a directory structure that can be used for authentication. Remember those migrationtools you installed?
- First off, we have to modify migrate_common.ph.
[root@ldapdev2 migrationtools]# vi /usr/share/migrationtools/migrate_common.ph
- Line 71 configures the mail domain. The comment says “dns domain”, which is a little different. In my environment, these are the same (hosts are hostname.domain.com, email is address@domain.com). If your email address was @mail.example.com, this might need tweeking. Otherwise, just make it example.com.
# Default DNS domain $DEFAULT_MAIL_DOMAIN = "padl.com";
- Line 74 configures the default base. This is the part of the directory that the migration tools will be accessing. Had you created some sort of structure already, you could use this to only modify part of your directory. We’re using it to create the base, and we’re not creating any sort of referral system.
# Default base $DEFAULT_BASE = "dc=padl,dc=com";
- Line 71 configures the mail domain. The comment says “dns domain”, which is a little different. In my environment, these are the same (hosts are hostname.domain.com, email is address@domain.com). If your email address was @mail.example.com, this might need tweeking. Otherwise, just make it example.com.
- Next, we’ll use migrate_base.pl to create base.ldif, which we’ll then import.
/usr/share/migrationtools/migrate_base.pl > ~/randotemp/base.ldif
- You can trim this output LDIF file down if you’d like, the only OUs i’ve used so far are People, Group and Mount.
- So now we import it:
[root@ldapdev2]# ldapadd -h localhost -x -W -D "cn=Manager,dc=example,dc=com" -c -f ~/randotemp/base.ldif Enter LDAP Password: adding new entry "dc=example,dc=com" adding new entry "ou=Hosts,dc=example,dc=com" adding new entry "ou=Rpc,dc=example,dc=com" adding new entry "ou=Services,dc=example,dc=com" adding new entry "nisMapName=netgroup.byuser,dc=example,dc=com" adding new entry "ou=Mounts,dc=example,dc=com" adding new entry "ou=Networks,dc=example,dc=com" adding new entry "ou=People,dc=example,dc=com" adding new entry "ou=Group,dc=example,dc=com" adding new entry "ou=Netgroup,dc=example,dc=com" adding new entry "ou=Protocols,dc=example,dc=com" adding new entry "ou=Aliases,dc=example,dc=com" adding new entry "nisMapName=netgroup.byhost,dc=example,dc=com"
That takes care of the minimal base, now lets get the necessary structure in place for autofs. This is pulled from Pat’s Daily Grind – AutoFS 5 and LDAP.
- We’re going to create three LDIF files and add them:
- auto.home.mounts.ldif
dn: ou=auto.home,ou=Mounts,dc=example,dc=com objectclass: automountMap objectclass: top ou: auto.home
- auto.master.mounts.ldif
dn: ou=auto.master,ou=Mounts,dc=example,dc=com objectclass: automountMap objectclass: top ou: auto.master
- home.auto.master.mounts.ldif
dn: cn=/home,ou=auto.master,ou=Mounts,dc=example,dc=com automountinformation: auto.home cn: /home objectclass: automount objectclass: top
- auto.home.mounts.ldif
- Import the files to the directory with ldapadd.
ldapadd -h localhost -x -W -D "cn=Manager,dc=example,dc=com" -c -f ./auto.home.mounts.ldif ldapadd -h localhost -x -W -D "cn=Manager,dc=example,dc=com" -c -f ./auto.master.mounts.ldif ldapadd -h localhost -x -W -D "cn=Manager,dc=example,dc=com" -c -f ./home.auto.master.mounts.ldif
- I’ll show you how to add a user to this config when we actually start adding users.
Intermission
So far, we’ve done the following:
- Installed the ldap server and clients
- Configured the ACLs
- Imported the minimal standard schema (plus AutoFS)
- Created a directory base that will work with the standard pam_ldap, nslcd, and nss-pam-ldapd utilities.
The road ahead:
- Our ACL won’t allow anonymous reads. We need to create the proxy user so that clients can access the directory
- We don’t have any users or groups yet
- I keep talking about AutoFS, so we’ll create the necessary directory entries for it and see an example of a working config as well.
Creating users and groups
This is pretty easy. We can either write up an ldif by hand and use ldapadd to add it, or we can use the migrationtools to create a template from an existing user. I don’t see any reason to put you through the migrationtools again, so I’ll paste an example of a working user and group.
- Create a new file called “<username>.ldif”, using the below as a template:
dn: uid=user1000,ou=People,dc=example,dc=com uid: user1000 cn: user1000 objectClass: account objectClass: posixAccount objectClass: shadowAccount objectClass: top userPassword: {SSHA}xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx loginShell: /bin/bash uidNumber: 1000 gidNumber: 1000 homeDirectory: /home/user1000 gecos: user1000,,, dn: cn=user1000,ou=Group,dc=example,dc=com objectClass: posixGroup objectClass: top cn: user1000 userPassword: {crypt}x gidNumber: 1000- Customize to meet your needs. This LDIF has everything you need to create a working user and his username group (ala standard linux host account). You’ll need to do one of these for the proxyuser we configured during the ACL step, in addition to a regular user. For the proxyuser, I set the shell to /bin/false and made his uidNumber/gidNumber 999. All my other users will be 1000+.
- Use the slappasswd command to generate an initial password, and paste it into the userPassword field of the user section. Do not set a password for the group, I don’t even know what that would do.
- If you want to configure an automount
/homedirectory for this user, you can do so by adding this to theusername.ldif:dn: cn=user1000,ou=auto.home,ou=Mounts,dc=example,dc=com automountinformation: nfsfileserver01:/local/path/to/home/user1000 cn: user1000 objectclass: automount objectclass: top
- You’ll need to create the home directory on the NFS file server, and you’ll have to have the LDAP and IDMAP clients working properly there. If you want, you could add this little bit of code to
/etc/pam.d/system-authon the NFS server to have the home directory auto-created when the user logs in the first time:session optional pam_mkhomedir.so skel=/etc/skel umask=077
Reference: http://www.server-world.info/en/note?os=CentOS\_6&p=ldap&f=2
- I’m pretty sure you’d want to have your user log in to the NFS server via SSH first to have the home directory created, but it seems like it might work if you have them log in to any LDAP client server via SSH that has the appropriate automount hooks.
- You’ll need to create the home directory on the NFS file server, and you’ll have to have the LDAP and IDMAP clients working properly there. If you want, you could add this little bit of code to
- Use the ldapadd command to add the user.
ldapadd -h localhost -x -W -D "cn=Manager,dc=example,dc=com" -c -f ./user1000.ldif
- That’s it for adding users and groups. You can see how you’d modify this file to add either just a user or just a group.
Configuring your clients
Now that we have a server, a directory, and some entries, we can use this thing. We’ll go over how to configure the client machines, and at the end we’ll talk about the automount considerations. If you were planning on SCPing files to the client machine, make sure you install openssh-clients.
- Install the necessary packages:
openldap-clients nss-pam-ldapd autofs nfs-utils
- Copy over the host CA cert and toss it in
/etc/openldap/cacerts/. - Use authconfig to get a jump on modifying the config files.
authconfig --enableldap --enableldapauth --ldapserver=ldapdev.example.com --ldapbasedn="dc=example,dc=com" --enableldaptls --enablemd5 --update
- Configure the proxy user.
- First, edit
/etc/nslcd.confand add the proxy user information to the very bottom:binddn uid=proxyuser,ou=People,dc=example,dc=com bindpw verysecret
- Do the same to /etc/pam_ldap.conf – the syntax is identical. If you skip this step, your users will not be able to change their own passwords!
- Restart nslcd with
service nslcd restart
- You can log in with the user now. Do a test with
getent passwd, and you should see your user and the proxy user (after all of the local users). - If it doesn’t work, check
/var/log/messages. If it complains about not being able to talk to the ldap server,- Log in to the ldap server
- Stop the slapd service
- Issue
slapd -d acl - In another window, restart nslcd on the client, and try
getent passwdagain - The slapd debug output may show that the client doesn’t like the CA cert. I encountered this error on one of my boxes – it didn’t seem to be looking in
/etc/openldap/cacertsfor the cert. I had to add the following to /etc/nslcd.conf:tls_cacertfile /etc/openldap/cacerts/ldapdev.example.com.ca.crt
- First, edit
Lets get his home directory squared away.
- Open up
/etc/sysconfig/autofsand add this to the bottom:LDAP_URI="ldap://ldapdev.example.com" LDAP_NETWORK_TIMEOUT=8 SEARCH_BASE="dc=example,dc=com" MAP_OBJECT_CLASS="automountMap" ENTRY_OBJECT_CLASS="automount" MAP_ATTRIBUTE="ou" ENTRY_ATTRIBUTE="cn" VALUE_ATTRIBUTE="automountInformation"
- Finally, we have to configure autofs to use the proxy user (I’m not sure why autofs has to have it’s own config and can’t reference the other 9 config files, but whatever)
- Crack open
/etc/autofs_ldap_auth.confand make it look like this:<?xml version="1.0" ?> <!-- This files contains a single entry with multiple attributes tied to it. See autofs_ldap_auth.conf(5) for more information. --> <autofs_ldap_sasl_conf usetls="yes" tlsrequired="yes" authrequired="simple" user="uid=proxyuser,ou=People,dc=example,dc=com" secret="plaintextpassword" />
- Crack open
Bonus: Allowing only specific groups access to a host
In NIS, you can add users to a hostgroup, and be done with it. You can do similarly with LDAP, but it requires additional schema and filters and generally kind of looks nasty. I prefer to use the pam_listfile.so module to have pam look at a textfile full of users / groups to determine who can / can’t login. Check out this quick how-to for allowing groups, or this one for denying specific users..
- Create a new file called /etc/login.group.allowed. List your groups (local or LDAP) one per line.
[root@webservices01 pam.d]# cat /etc/login.group.allowed root admin-web
- Now we need to modify the pam stack to reference the new module and the flatfile. Add the following line to the top of==/etc/pam.d/system-auth= and
/etc/pam.d/sshdauth required pam_listfile.so onerr=fail item=group sense=allow file=/etc/login.group.allowed
Final thoughts
I need to add more instruction on which pre-reqs are needed for autofs on the clients, and I need to indicate when to bounce autofs. One more deployment to work out the kinks oughta do it.
SASL would be pretty great, since you could do passwordless SSH between hosts via the SASL-EXTERNAL mechanism. SASL is also necessary for Postfix and other applications, and even AutoFS is compatible with it.
Thanks for reading, and I hope you can learn from my experience.
Useful links
| Link | Description |
|---|---|
| http://www.computerglitch.net/bin/texts/CentOS6\_LDAP.php | Interesting notes on the user account creation and setting a user’s password, as well as his own “recipe”. Useful comparison. |
| http://www.openldap.org/faq/data/cache/185.html | The quick-n-simple TLS setup guide, although I hate the instructions on generating a CA cert. |
| http://www.tc.umn.edu/~brams006/selfsign.html | A better reference on creating SSL certs |
| http://manpages.ubuntu.com/manpages/karmic/man5/slapd-config.5.html | slapd-config man page |
| http://padraic2112.wordpress.com/2007/04/03/autofs-5-and-ldap/ | Good for creating the autofs entries |
| http://www.server-world.info/en/note?os=CentOS\_6&p=ldap&f=1 | Nice general ref for centos6 services, has un-explained configs that are worth thinking about / comparing to your setup |
| http://serverfault.com/questions/323497/how-do-i-configure-ldap-on-centos-6-for-user-authentication-in-the-most-secure-a | Another useful recipe, although he has a half broken DB Monitor config. |
| http://eatingsecurity.blogspot.com/2008/11/openldap-security.html | This is where I got turned on to the Proxy User. He only discusses it at a high level, and doesn’t discuss the ACL in detail. |
| http://www.cyberciti.biz/tips/howto-deny-allow-linux-user-group-login.html | Configuring login access based on group membership |