LDAP Auth on Debian Sarge HOWTO
Last updated: 2006-10-17
This HOWTO explains how to set up LDAP based authentication and host login
authorization on computers running the Sarge (3.1) release of Debian GNU/Linux.
All the information in /etc/group, /etc/passwd, and /etc/shadow can be
stored in an LDAP database (though you may want to leave system groups and
accounts, including root, configured in these files) for centralized management
of this information amongst many computers. Additionally, this HOWTO will
explain how you can limit login to certain hosts for each user in your LDAP
database.
LDAP allows you to store many other types of information in each record for a user, group, etc. For example, you can keep track of users' email addresses, and many address book and email client applications can get this information directly from your LDAP server. Or, you could use a separate password for your users' email authentication from what they use to log in to the system, and store that password as an attribute on the user's LDAP record. An LDAP database can even be used with Active Directory to authenticate Windows users. This HOWTO will not go into detail about how to set any of these up, though. We'll just focus on login authentication and authorization for Debian clients, and the Debian LDAP server.
Throughout these examples we will call our example LDAP server ldap.example.org.
Wherever you see this host name, use instead the actual fully quaified domain
name of your LDAP server. Additionally, whenever we give the dn suffix
dc=ldap,dc=example,dc=org, replace each dc=x with the corresponding word
from your LDAP server's fully qualified domain name.
LDAP Server
This machine will store the LDAP database and listen to queries from LDAP clients over the network. On a network which is not protected from malicious packet sniffing or other network attacks, it would be a very good idea to set up the LDAP server to require clients to connect via SSL, particularly if user passwords are being authenticated with LDAP. Additionally, if you are in a high traffic/high availability environment, it would be wise to have multiple LDAP servers with replication. This HOWTO will not cover SSL or replication with LDAP, however.
Install and Configure
So, on to setting up your LDAP server. You will use the slapd server from OpenLDAP. To install, just do:
apt-get install slapd ldap-utils
Answer the questions you are given by dpkg as in here:
Omit OpenLDAP server configuration? no
DNS domain name: ldap.example.org
Name of your organization: example_organization
Admin password: <administrative LDAP password>
Database backend to use: BDB
Do you want your database to be removed when slapd is purged? no
Allow LDAPv2 protocol? no
Change ldap.example.org to the fully qualified domain name of your LDAP server as noted above, and example_organization to the name of your organization. The Admin password question should be answered with a relatively strong password--a user with this password will be able to modify any LDAP record he/she wishes.
Set Up Base Information and Test User and Group
Now, download some basic LDIF files to set up base user and group information,
and create an initial test user and group. Download
base.ldif,
mygroup.ldif, and
myuser.ldif. Modify
them as you see fit for your site (for example, make sure the given uid and gid
numbers aren't already in use), and update your LDAP database with the following
commands (remember to modify the dc=ldap,dc=example,dc=org parts as
appropriate):
ldapadd -x -D "cn=admin,dc=ldap,dc=example,dc=org" -W -f base.ldif
ldapadd -x -D "cn=admin,dc=ldap,dc=example,dc=org" -W -f mygroup.ldif
ldapadd -x -D "cn=admin,dc=ldap,dc=example,dc=org" -W -f myuser.ldif
Allow Users to Modify Attributes
Add the following to /etc/ldap/slapd.conf right after the similar block about
access control to the password (access to attrs=userPassword...) to allow
users to modify some attributes that they should be able to modify themselves.
access to attrs=loginShell,shadowLastChange,gecos
by dn="cn=admin,dc=ldap,dc=example,dc=org" write
by self write
by * read
Now, restart the LDAP server:
/etc/init.d/slapd restart
LDAP Client
Each client machine that you wish to use for LDAP authentication. must be set up as follows.
Install and Configure
apt-get install ldap-utils libpam-ldap libnss-ldap nscd
Answer the questions from dpkg for libpam-ldap and libnss-ldap as given on this page, but use md5 for passwords instead of exop:
LDAP Server host: 1.2.3.4
The distinguished name of the search base: dc=ldap,dc=example,dc=org
LDAP version to use: 3
Database requires login? no
Make configuration readable/writeable by owner only? yes
The distinguished name of the search base: dc=ldap,dc=example,dc=org
Make local root Database admin: yes
Database requires logging in: no
Root login account: cn=admin,dc=ldap,dc=example,dc=org
Root login password: <enter LDAP admin password here>
Local crypt to use when changing passwords: md5
The root login password prompted for will be the same as the password you
entered above when configuring the server, so clients can connect to the LDAP
server as the administrative user from the root account on the client. Saying
"yes" to "Make local root Database admin" will create a file called
/etc/ldap.secret that has the administrative LDAP user's password in it. This
file is only readable by the root user, but you may not wish to have this
password written to disk in clear text, anyway. Probably a better thing to do
than this is to put some users in an administrator group, then use ACLs on the
LDAP server to allow that group's members to modify any LDAP attribute they
wish. For the purposes of this howto, though, we will assume you allow the root
user to do anything by virtue of being able to read the /etc/ldap.secret file.
It is arguably not as secure, but it is simpler.
Configure Name Service Switch
We want the system to first try to get user and group information from LDAP,
and, failing that, try the old method (passwd and group files). The C library
has numerous functions that deal with user and group information such as
getpwnam() and getgrent(), and the name service switch is the method it uses
to determine what type of databases to look at for this info (files like
/etc/passwd, NIS, LDAP, etc). Edit /etc/nsswitch.conf and make sure you have
these lines:
passwd: ldap compat
group: ldap compat
shadow: compat
Note that shadow: does not have ldap included. It does not seem to be
necessary, and I suspect that it may cause pam_check_host_attr in your PAM
configuration to not function properly. By using LDAP for authentication,
password shadowing isn't necessary anyway (the LDAP server's ACLs prevent
non-administrative users from seeing other users' hashed passwords). Next add
the following to /etc/ldap/ldap.conf:
BASE dc=ldap,dc=example,dc=org
URI ldap://128.208.123.108
Then restart nscd, the name service caching daemon (this daemon prevents the client from having to query the LDAP server every time you run, for example, ls):
/etc/init.d/nscd restart
PAM
Now we will modify PAM configuration files to actually set up LDAP authentication and authorization. PAM will be set up to first attempt to authenticate a user against the local passwd/shadow files, then try LDAP.
Require Strong Passwords
Before we get to messing with the PAM LDAP stuff, let's install the PAM passwdqc
plugin which enforces strong passwords on users. It is more configurable and can
be more restrictive than cracklib. Later on we will enable it in
/etc/pam.d/common-password
apt-get install libpam-passwdqc
/etc/pam.d Common Files
Debian has a series of files in /etc/pam.d appended by common- at the
beginning of their names, which are included by the other files in that
directory for specific services. We can tell PAM to use LDAP for all of these
services by modifying these common files.
In /etc/pam.d/common-password, comment out and replace:
password required pam_unix.so nullok obscure min=4 max=8 md5
or:
password required pam_cracklib.so retry=3 minlen=6 difok=3
password required pam_unix.so use_authtok nullok md5
with:
# try password files first, then ldap. enforce use of very strong passwords.
password required pam_passwdqc.so min=disabled,16,12,8,6 max=256
password sufficient pam_unix.so use_authtok md5
password sufficient pam_ldap.so use_first_pass use_authtok md5
password required pam_deny.so
Read the pam_passwdqc man page for more about parameters you can give to it.
In /etc/pam.d/common-auth comment:
auth required pam_unix.so nullok_secure
replace with:
# try password file first, then ldap
auth sufficient pam_unix.so
auth sufficient pam_ldap.so use_first_pass
auth required pam_deny.so
In /etc/pam.d/common-account comment:
account required pam_unix.so
replace with:
# try password file first, then ldap
account sufficient pam_unix.so
account sufficient pam_ldap.so
account required pam_deny.so
There is generally no need to modify /etc/pam.d/common-session, but you may
wish to invoke pam_mkhomedir.so from this file to automatically create home
directories for users when they first log in. I have not personally used this
method before as I have either had already existant home directories mounted via
NFS, or created them using Splat.
Restrict Login Access via Host Attribute
Now we can tell PAM that user's need a Host: attribute in their LDAP entry
matching a * or the host's name in order to log in. Add the following to /etc/
pam_ldap.conf:
# allow users with host attributes of either example or * to log in
pam_filter |(host=example)(host=\\*)
Replace example in the above with the name of the host you are configuring PAM on now.
Restart ssh (have to stop it and start it again):
/etc/init.d/ssh stop
/etc/init.d/ssh start
Restarting cron is also a good idea:
/etc/init.d/cron stop
/etc/init.d/cron start
User Management
Once you have done the above steps and verified that logging in with a test
user you've created in LDAP, which does not exist in your password file, it
should be safe to start migrating users and groups to LDAP and removing them
from the shadow, passwd, and group files. Take a look at the migrationtools
package for some utilities that will help speed this along.
apt-get install migrationtools
Also, the following sections give more information on managing users and groups in LDAP.
ldapvi
ldapvi is a very useful utility. It allows you to edit your LDAP database
directly within the vi text editor. To install:
apt-get instal ldapvi
Then, to use it:
ldapvi -D "cn=admin,dc=ldap,dc=example,dc=org"
This will prompt for your LDAP password, then open a textual version of the
database in vi. Make whatever changes you wish, such as adding a host
attribute to a user's record or changing someone's name, and :wq to exit.
ldapvi will make sure your changes keep all records valid, asks you to verify,
then updates the database if it can.
Creating and Deleting Users and Groups
I've written scripts to add and delete users and groups using LDAP. They are
included here:
ldap_adduser.pl,
ldap_addgroup.pl,
ldap_deluser.sh,
and
ldap_delgroup.sh.
All of these scripts have hard coded server names and/or a base dn that you will
have to change for your own LDAP server. Also, all are intended to be run only
by the root user (they need to be able to read /etc/ldap.secret, which should
be readable only by root, and ldap_adduser needs to be able to create home
directories and change ownerships). Both the user and group adding scripts need
Net::LDAP, available in libnet-ldap-perl:
apt-get install libnet-ldap-perl
Please note that the user and group creation scripts above both may suffer a race condition if either is being run more than once simultaneously. The user or group creation script checks to see if a username or group name is in use, and fails if it is. However, some time passes between this check and when it actually adds the record to LDAP. Fortunately, the LDAP add operation will likely fail if someone creates a user or group with the same name at the same time as you, because the LDAP server should not allow multiple records with the same username or group name (they would have the same dn, if it did). Unfortunately the same is not true for numeric user ID or group IDs. Multiple simultaneous instances of the add group/user scripts can very likely end up creating two different users or groups with the same numeric ID. So, try to make sure that nobody else is creating users or groups at the same time as you if you choose to use these scripts.
The delete scripts are just shell scripts, however, so they only need the basic
LDAP shell utilities that you should have gotten with ldap-utils. I believe
they also do not have the same race condition problems that the creation scripts
have (if the delete script runs on the same user or group simultaneously, the
first should delete successfully and the second one should just fail). I just
copied these scripts to /usr/local/sbin/ on my system.
If you wish to put add or remove user's from groups, I recommend just using
ldapvi to add or remove a memberUid attribute (set to the user's username)
to the appropriate group.
chsh and chfn
The normal Debian chsh and chfn will fail to work after you have moved your
user's from the passwd/group/shadow files to LDAP, though passwd will continue
to work properly for changing user passwords. Fortunately, however, the
libpam-ldap package includes some handy dandy new versions of these programs
in /usr/share/doc/libpam-ldap/examples. You need to install the package
libnet-ldap-perl (as above for ldap_adduser.pl and ldap_addgroup.pl) for
them to work. You can just copy these to /usr/local/bin/ or something, or
replace the system's versions of these as follows:
dpkg-divert --add --rename --divert /usr/bin/chfn.local /usr/bin/chfn
dpkg-divert --add --rename --divert /usr/bin/chsh.local /usr/bin/chsh
ln -s /usr/share/doc/libpam-ldap/examples/chsh /usr/bin/chsh
ln -s /usr/share/doc/libpam-ldap/examples/chfn /usr/bin/chfn
A Note About nscd
Each LDAP client uses something called nscd to cache LDAP information, and reduce load on the LDAP server so that it isn't queried every single time someone checks ownership on a file by running ls or something. Because the LDAP records may be cached, it may take a few minutes for changes you make to a user or group LDAP record to propogate to all LDAP clients.
References and Acknowledgments
http://aqua.subnet.at/~max/ldap/
http://www.metaconsultancy.com/whitepapers/
http://enterprise.linux.com/enterprise/05/09/15/1930256.shtml?tid=129
http://wiki.acm.jhu.edu/w/Central_authentication
http://www.gentoo.org/doc/en/ldap-howto.xml
Thanks also to Chris Frederick, Rich Henning, David Mitchell, Szymon Bobek, and Jason for pointing out various errors/bugs in my text, scripts, and configs!