Posts Tagged ‘authentication’
Firstly, be warned – this is a long article. LDAP is non-trivial, but if you’ve mastered NIS/NFS, this is the next step :-)
The Lightweight Directory Access Protocol, better known as LDAP is what is known as a directory service, much like Windows’ Active Directory. Indeed, Active Directory is the Windows implementation of LDAP so you’ve probably heard to LDAP without even being aware of it :-) Like Active Directory, you can store all sorts of information in an LDAP database and because it’s standards-based and cross-platform, you can read this information securely from anywhere using any LDAP-aware application. Strictly speaking, LDAP isn’t a database system but a protocol used to access information stored in an information directory also known as an LDAP directory. LDAP is particularly useful for storing information that you wish to read from many locations, but update infrequently.
While you can store all sorts of information in an LDAP directory, we’re going to use it to store Linux user login credentials and access the LDAP directory whenever we want to login to any machine on our network rather than the local user credentials. Assuming you’ve been wanting to set up something like this, you may be asking why you don’t just use NIS/NFS. In the past encrypted passwords contained in ‘/etc/passwd’ or ‘/etc/shadow’ were distributed by NIS, thus making it act as an authentication as well as authorisation server. Nowadays, this technique is not so suitable because it involves moving the password over an open and insecure network where a sniffer could capture it and, with the processing power currently available, unencrypt it in a few machine hours. NIS is fine for simple solutions on an trusted intranet but unsuitable as an enterprise solution. Also, unlike NIS, LDAP is expandable, which means that the type of data it can represent is not established beforehand by the protocol, but can be changed by the administrator by adding schemas. NIS operates on “flat” domains and is therefore unsuitable for large organisations which due to their nature may be organised hierarchically in a “tree” structure.
Fedora ships its own LDAP based server but we will be using the OpenLDAP implementation with Berkley Database (bdb) as the database backend. Data is entered into the LDAP server via plain text LDIF (LDAP Data Interchange Format) files.
This exercise assumes that you’ve got a networked Fedora install working and that you’ve assigned it a host name that is reachable via DNS. If you don’t have a static IP address that you can assign a host name, you can set one up using Dynamic DNS. Make note of the IP address of the server – for the purposes of this, I’ll assume it’s ’192.168.1.2′ internally as we’re using this on a home network.
If you want to test that your server which you’re going to use as a LDAP server on your network has a fully qualified domain name (FQDN), you can run: -
Configuring the LDAP server
Obviously, you’ll also need to be root for this :-) Okay, let’s get started. First you’ll need to install the OpenLDAP packages.
yum install openldap-servers migrationtools openldap openldap-clients openldap-devel nss_ldap
Next, you’ll need to create an LDAP root user – this is similar to a regular Linux root user in that it has entire control over your LDAP directory service. Do so with: -
This will ask you to enter a password and return the SHA-encrypted hash of the password. It will be something like: -
Make a note of this string, as you will need it later on.
First you need to set up an LDAP user. Enter the following commands: -
and set a password for it.
Next, you need to set up a directory for your database and give is the right access permissions. We’re going to use the domain ‘ldap.test.lan’
…and similarly give our LDAP users access permissions: -
chown -R ldap.ldap /var/lib/ldap/ldap.test.lan
The base configuration
Now we need to set up our base configuration. You’ll need to delete the /etc/openldap/slapd.d directory or rename it as else Fedora will ignore our configuration and use the one under slapd.d. I’m just going to rename it.
mv /etc/openldap/slapd.d /etc/openldap/slapd.d.DEFAULT
Then we’ll create a configuration file. This is actually the “old” way of doing things, but it’s far simpler than running through the mess of auto-generated configuration files under the slapd.d sub-directory.
Add the following, changing the example host for yours.
This creates database of the default type ‘bdb’ (Berkeley Database) using the domain suffix ldap.test.lan made up of domain components (DCs) ‘ldap’, ‘test’ and ‘lan’. It then creates the root user with a common name (CN) or nickname of ‘admin’ who, as expected, is part of the ‘ldap’, ‘test’ and ‘lan’ DCs. Lastly, it defines the encrypted version of the LDAP root password you created earlier as well as the location of the LDAP database within the file system and tell LDAP where to find the certificate and key files for encryption.
Because we are using LDAP for authentication across a network, we’ll need to encrypt the traffic, which is what the encryption key entries above are all about and is one of the key differences with something like NIS. We need to tell Fedora how to start the secure LDAP daemon which is done by editing the sysconfig entry for ldap: -
Add the following line or uncomment the one that’s there and set it to ‘yes’.
Save this and return to the command line. We can now run LDAP on default port of 389 with TLS. Of course, we’ll have to create some encryption keys for this. Run the following which will create encryption keys in the location we specified in the ‘/etc/openldap/slapd.conf’ file:-
openssl req -newkey rsa:1024 -x509 -nodes -out /etc/openldap/ssl/ldap-server.pem -keyout /etc/openldap/ssl/ldap-server.pem -days 365
Make sure the following sections are filled in with your host details.
Common Name (eg, your name or your server's hostname) : ldap.test.lan
Email Address : firstname.lastname@example.org
You also need to set these directories to something that the ldap user can read: -
chown -rf root.ldap /etc/openldap/ssl
chmod -rf 750 /etc/openldap/ssl
Check that the ‘/etc/openldap/ssl/ldap-server.pem’ private key file exists and is of the right format: -
It should look something like: -
-----BEGIN RSA PRIVATE KEY-----
-----END RSA PRIVATE KEY-----
Each client will need the ‘certificate’ part of the file, so we can use the grep command to extract this information.
grep -A 100 CERTIFICATE /etc/openldap/ssl/ldap-server.pem > /etc/openldap/ssl/ldap-client.pem
The ‘/etc/openldap/slapd.conf’ file now references our key to activate TLS encryption of all incoming connections to the server. The LDAP daemon won’t start properly unless the files in the ‘/etc/openldap/ssl directory’ are owned by the ldap user. We need to make sure of this with: -
chown -R ldap.ldap /etc/openldap/ssl
The next step is to configure the migration tools used to migrate your existing users into LDAP. To do this, you need to edit the migrate_common.ph file: -
The only things you need to change are the lines below. The DEFAULT_BASE should be set to your host.
# Default DNS domain
$DEFAULT_MAIL_DOMAIN = "localhost";
# Default base
$DEFAULT_BASE = "dc=ldap,dc=test,dc=lan";
You now need to copy a default DB_CONFIG file which sets cache and tuning options for the Berkley database backend (this also needs to be writeable by the ldap user). This file may be under a different directory depending on your version of Fedora, but you can find it with: -
find /usr -name "DB_CONFIG.example" -print
Assuming this is found in ‘/usr/share/openldap-servers/DB_CONFIG.example’, you need to copy this example file to your /var/lib/ldap directory and rename it as DB_CONFIG.
cp /usr/share/openldap-servers/DB_CONFIG.example /var/lib/ldap/DB_CONFIG
Once you’ve done this, you need to make sure that the ldap user has access to it: -
chown -rf ldap.ldap /var/lib/ldap
Lastly, test your configuration by running the command, and check that it returns ‘config file testing succeeded’:-
If you have no problems, you’ve successfully completed your basic LDAP server configuration. You should now be able to start your slapd service with the following: -
service slapd start
You can test that the service started correctly and is listening on the LDAPS port with: -
netstat -lt | grep ldap
You should get back something like: -
tcp 0 0 *:ldap *:* LISTEN
tcp 0 0 *:ldaps *:* LISTEN
If everything looks good, set slapd to start on boot with: -
chkconfig slapd on
To test the server configuration, run: -
ldapsearch -x -b '' -s base '(objectclass=*)' namingContexts
which should return success as below: -
# extended LDIF
# base <> with scope baseObject
# filter: (objectclass=*)
# requesting: namingContexts
# search result
result: 0 Success
# numResponses: 2
# numEntries: 1
We should now have a base LDAP server running and configured for our LDAP domain. However we do not have any users (People) or groups (Group) configured from our /etc/passwd, /etc/shadow and /etc/group files. So now we need to set up our base, authentication and group files. This is done via a migration of your existing local UNIX accounts already configured on the server which are converted into an LDIF file for loading into LDAP. First however, we need to create a template ‘base.ldif’ file which creates the base structure of our directory (ldap.test.lan), which we will import into the LDAP database first.
Configuring the base LDAP entry
Add the following, replacing dn and dc entries with the dc’s from your host.
Now that we have the base information for our LDAP database structure, we can import that information into our LDAP database (using the password you created above:-
ldapadd -x -W -D "cn=admin,dc=ldap,dc=test,dc=lan" -f ~/base.ldif
You should get some output similar to the following: -
Enter LDAP Password:
adding new entry "dc=ldap,dc=test,dc=lan"
adding new entry "ou=People,dc=ldap,dc=test,dc=lan"
adding new entry "ou=Group,dc=ldap,dc=test,dc=lan"
Importing users as LDAP People entries
Now, we will use the migration script whose settings we modified earlier to create an .ldif file which we will use to populate LDAP with all our existing users pulled from ‘/etc/passwd’.
/usr/share/migrationtools/migrate_passwd.pl /etc/passwd ~/people.ldif
Once you’ve created this .ldif file, the entries can be imported into LDAP:-
ldapadd -x -W -D "cn=admin,dc=ldap,dc=test,dc=lan" -f ~/people.ldif
Importing groups as LDAP Group entries
We will now do the same with the user groups with the following: -
/usr/share/migrationtools/migrate_group.pl /etc/group ~/group.ldif
…and then import the group entries into LDAP: -
ldapadd -x -W -D "cn=admin,dc=test,dc=lan" -f ~/group.ldif
Now that we have our LDAP database populated with user information, it’s time to test our work. You can use the ldapsearch command to look for your username as below: -
ldapsearch -x "cn=[user]"
You should get something back like: -
# extended LDIF
# user, Group, ldap.test.lan
# search result
result: 0 Success
Add new LDAP People/Group entries
That will have imported the user details present on the server into LDAP. But it’s safe to assume that you’ll want to add other users. To add a new user, you’d create a .ldif for the user account and the group. Then we import these files into the LDAP server like we did with the base, people and groups details previously.
For example, if I wanted to add a user called ‘david’, I’d create a ‘david.ldif’ file such as below: -
…and populate it with: -
cn: David Lightman
gecos: David Ligntman
Then the same process for the group: -
Populated with: -
You’ll notice the password has an ‘x’ in it, much like the ‘/etc/passwd’ entry for the encrypted password, as all passwords are kept in ‘/etc//shadow’ these days. Similar format, though. Lastly, these files will be added to LDAP: -
# ldapadd -x -W -D "cn=admin,dc=ldap,dc=test,dc=lan" -f ~/david-user.ldif
Enter LDAP Password:
adding new entry "uid=david,ou=People,dc=ldap,dc=test,dc=lan"
# ldapadd -x -W -D "cn=admin,dc=ldap,dc=test,dc=lan" -f ~/david-group.ldif
Enter LDAP Password:
adding new entry "cn=david,ou=Group,dc=ldap,dc=test,dc=lan"
…and you should now have a new user called ‘david’. The absolute last thing you need to do is open a port in your firewall for LDAP to listen on. Since the default LDAP port is 389, we’ll open that using iptables.
iptables -A INPUT -m state --state NEW -m tcp -p tcp --dport 389 -j ACCEPT
That’s the LDAP server configuration and data migration done.
Client LDAP configuration
Right, the next next is to step up a client Fedora system to authenticate via the LDAP server. First, make sure you have installed the required packages: -
yum -y install openldap openldap-clients openldap-devel nss_ldap
LDAP clients are configured using the ‘/etc/openldap/ldap.conf’ file. You need to make sure that the file refers to the LDAP server’s IP address for the domain ‘ldap.test.lan’ which we set up. So, edit the config file with: -
Make sure it looks something like this: -
Next, we’ll need to tweak the ‘/etc/nsswitch.conf’ file. This configuration file defines the order in which the operating system searches login databases for login information when users attempt to login. You’ll want to configure it to first search its ‘/etc/passwd’ file. If it doesn’t find the user password information there, it goes to the LDAP server. The easiest way set this up is to use the ‘/usr/bin/authconfig-tui’ command, which provides a graphical tool.
1. Select LDAP.
2. Give the LDAP server’s IP address, which is 192.168.1.2 in this case.
3. Give the base DN as dc=ldap,dc=test,dc=lan
4. Select TLS.
5. Use MD5 and shadow passwords.
When you’re done, look at the ‘/etc/nsswitch.conf’ file and make sure it has references to LDAP. It should look something like: -
passwd: files ldap
shadow: files ldap
group: files ldap
hosts: files dns
bootparams: nisplus [NOTFOUND=return] files
netgroup: files ldap
automount: files ldap
aliases: files nisplus
You’ll need to copy the encryption key from the server’s ‘/etc/openldap/ssl/ldap-client.pem’ location to ‘/etc/openldap/cacerts’. You can use sftp for this: -
# cd /etc/openldap/cacerts
# sftp email@example.com -p 22
You previously created a user named ‘ldap’ in the group on the LDAP server. You now need to make sure that this user has a home directory on the LDAP client. The example in this section creates the directory and makes ldap the owner. As you can see, the LDAP server correctly gets its user information about ‘ldap’ from 192.168.1.2; the chown command doesn’t complain about the ‘ldap’ user not existing in the client’s ‘/etc/passwd’ file.
Check that the ldap user doesn’t exist in the client’s ‘/etc/passwd’ file.
grep ldap /etc/passwd
There shouldn’t be anything returned. Next, you’ll create the home directory, copy a Bash login profile file into it, and modify the ownership of the directory and all the files to user ‘ldap’:-
# mkdir /home/ldap
# chmod 700 /home/ldap/
# chown -R ldap.ldap /home/ldap
# ls -la /home
Next you need to edit the /etc/ldap.conf file: -
And make sure it looks something like: -
Testing your LDAP client/server setup
Restart your LDAP server service to make sure all configuration is loaded and then to test, open another terminal window on the client and try to login as an LDAP-only user, such as the ‘david’ account we set up earlier: -
su - david
You should be able to login fine! :-) If not, check your /var/log/messages file for any error messages which might tell you what went wrong. But that is about it! Further documentation on the uses of LDAP can be found here.
To login to any Linux machine, you need a username/password pair that is valid on that machine via the /etc/passwd file and the shadow file. This can become a problem if you have more than one Linux machine on your network as you have to maintain a separate user account on each system which isn’t very goof for network transparency.
I’ve already talked about NFS, the Network File System and how you can use auto-mount to transparently share directories across a network. NIS or Network Information Service is built on top of NFS to transparently provide files and advanced services that do not fix into a specialised service such as DNS, the Domain Name System. If you think about it, this makes sense as everything under Linux is a file or a directory. Here, we’re going to set up our NIS server to hold one set of user credentials and use a client Linux system to use those credentials to log in. We’ll then export that user’s home directory using NFS so that their home environment and account credentials can be used on any Linux client on your network.
Firstly you need to verify that you have the packages required to implement NIS. I’m using Fedora 15 for this exercise, but any RPM/Yum-based distribution will work. Debian/Ubuntu users will have to use apt-get to get the required packages.
yum install ypserv ypbind yp-tools
Before getting started with the configuration, you need to decide what your server’s NIS domain is. Each NIS server will only serve clients from the domain it is part of. This allows you to “cut up” your network into virtual sections and have an NIS server on each. Clustering, if you will.
One thing to make very clear here that the NIS domain name is not the same thing as the DNS domain name. In fact, your DNS domain and NIS domain should be different for security reasons.
As the NIS server only listens to clients within the same NIS domain, you need some method to add clients to an NIS domain. On each machine that will authenticate with the NIS server (including the NIS server itself), you’ll need to install ypbind and rpmbind: -
yum install ypbind rpcbind
Once these are installed, on each client run: -
You also need a method to have this command run at system boot. Fortunately, you can simply add the following line to ‘/etc/sysconfig/network’ file with: -
adding line: -
where test.nisdomain.net is the NIS domain I’m going to use.
NIS Server Configuration
Now that we’ve got all the machines on the same NIS domain, we need to start configuring the NIS server. We’ll assume this server has an IP address of 192.168.1.2. On the server as root, open the /etc/ypserv.conf file with: -
and look for the lines below. These will be commented out by default, so press ‘i’ and uncomment them so they read: -
* : passwd.byname : port : yes
* : passwd.byuid : port : yes
This makes sure that authentication on the server is required, else any machine on the network could issue the ‘ypcat passwd’ command and read the entire passwd database exported by the NIS server regardless of domain.
Next, you need to set what services to provide via NIS. Open the Makefile with: -
and looks for the below line.
# If you don't want some of these maps built, feel free to comment
# them out from this list.
all: passwd group\
# all: passwd group hosts rpc services netid protocols mail
# netgrp shadow publickey networks ethers bootparams printcap \
# amd.home auto.master auto.home auto.local passwd.adjunct \
# timezone locale netmasks
This defines all the files to be made available in the NIS domain. As NIS can be used for more than the user authentication we are going to do, you can see that you could even make available say – the /etc/hosts file where each machine looks for hosts it knows about before handing off to the domain name servers further up the Internet hierarchy. So you could use NIS to rig up a little home DNS system, for example :-) THis might even be useful, as for small networks, setting up bind for DNS may not be worth the hassle. We’re just going for centralised user authentication here, so make sure that passwd and group file names are un-commented but the default is fine. Just make sure /etc/passwd and /etc/group are able to be exported.
Save this file and verifying you’re in the same directory as the Makefile, run: -
This will create the NIS database maps. You will need to run this every time you change any source file listed in the /var/yp/Makefile as above. For example, when you add/remove a user from the /etc/passwd file on the NIS server. Changes to passwords do not require a make as they are held in the /etc/shadow file which should NOT EVER be exported on an NIS server :-)
If the make fails, make a note of which files gave the error and then edit /var/yp/Makefile, search for the “all” entry and comment out the files that gave the error. Run the make again.
The next file you need to edit is ‘/var/yp/securenets’. This file defines
the NIS clients that are allowed to access your NIS server. This file only
takes IP addresses and not hostnames. The IP addresses are specified as a netmask/IP address pair. ‘Localhost’ will need to be in this file. The entry should already be there, but if not then enter the following:-
This essentially lets all machines on the local private network (192.168.1.*) and the localhost access the NIS server. You can also allow specific hosts access to the NIS server by giving the keyword “host” followed by an IP address.
Now you need to start the server. The portmap daemon must be started before the ypserv daemon so run the following in the order shown: -
Verify the server started correctly with: -
It should output similar to: -
00004 2 udp 1003 ypserv
100004 1 udp 1003 ypserv
100004 2 tcp 1006 ypserv
100004 1 tcp 1006 ypserv
If you want your users to be able to change their user account passwords over the network, you now need to start the yppassword daemon with: -
This needs to be started after the other daemons mentioned above, but not if you don’t want to allow your users this functionality.
Users who want to change their password will have to use the ‘yppasswd’ command rather than the usual ‘passwd’ command. I guess you could add an alias to your ~/.bashrc file…
…assuming that is all passwd is used for :-) But that should work, or simply remind your users to use ‘yppasswd’.
NIS Client Configuration
On each client, edit the /etc/yp.conf file: -
The default file will have all entries commented out but will look a little like: -
# /etc/yp.conf - ypbind configuration file
# Valid entries are
# domain NISDOMAIN server HOSTNAME
# Use server HOSTNAME for the domain NISDOMAIN.
# domain NISDOMAIN broadcast
# Use broadcast on the local net for domain NISDOMAIN
# domain NISDOMAIN slp
# Query local SLP server for ypserver supporting NISDOMAIN
# ypserver HOSTNAME
# Use server HOSTNAME for the local domain. The
# IP-address of server must be listed in /etc/hosts.
# If no server for the default domain is specified or
# none of them is rechable, try a broadcast call to
# find a server.
It will contain a list of all the NIS servers in this NIS domain. You can specify as many NIS servers here as you like, but for a small network, you only need the one we configured above.
While NIS doesn’t use DNS, the server list can contain host names as well as IP addresses as long as the host name is listed in that machine’s /etc/hosts file. However here we’ll use just IP addresses as my home network is small.
The next thing to do is to remove the users that will be authenticated against NIS from the local client system if these users exist there. This is because when authenticating a user login, the client system will first check for the user in it’s local ‘/etc/passwd’ and ‘/etc/shadow’ files and then only check NIS if the user doesn’t exist locally. You can see this in action with the ‘/etc/nsswitch.conf’ file which has commented out sections for each file location the system should check for authentication for users, passwords and groups.
passwd: files nisplus nis
shadow: files nisplus nis
group: files nisplus nis
You can see above that the local files are checked before NIS is for users. I would recommend making a backup of these files before you starting deleting entries :-)
cp /etc/passwd /etc/passwd.BACKUP
cp /etc/shadow /etc/shadow.BACKUP
cp /etc/group /etc/group.BACKUP
Then use vi to delete each user entry that will be used by NIS from the /etc/passwd, /etc/shadow and /etc/group files.
The above system for the /etc/nsswitch.conf file is how Fedora does it. It’s simple and effective and if you like, you can skip to starting the client daemon.
However if you want more fine-grained control or you’re using a different distribution, you can change the nsswitch.conf entries for each entry to: -
Save this and at the bottom of the /etc/passwd file, you need to add the following line: -
For the /etc/group file, add the following line to the bottom: -
The above ‘+’ entries means that anyone who is in the NIS password database will be able to login to this machine. If however, you want to limit access to certain users or groups, edit your ‘/etc/passwd’ file and replace the ‘+::::::’ with:-
In this example, user1 has access to the NIS server, so does user2 but they cannot log in to this machine and also the network group nisgrp is allowed. To disallow access to few users/netgroups prefix the username with a ‘-’ instead. Also make sure that ‘+::::::’ is a the bottom of the file and your entries appear above it.
Lastly, you need to start up the ypbind daemon.
You can test your NIS configuration now by attempting to login on the client machine with a user that you know is only in the NIS server’s /etc/passwd file. If the login is successful then your NIS setup is
Server NFS Configuration
Now that the login procedure has been setup, you need to ensure that the users have access to their home directories. If users currently have home directories on a client machine, this will need to be copied with something like ftp, scp or sftp commands to the NIS server as it’s /home directory will store all the home directories of the users using NIS.
You can copy the user home directories on each client to the NIS server’s /home with something like: -
This will copy the client contents of /home/user1 to /home/user1 on the NIS server.
As in my NFS article, the aim of NFS is to transparently share directories present on a server to a client so it looks like part of the local file system. Which is exactly what we want because we want the client to think it’s NIS-served /home directory for user1 is actually on the local client file system. Perfect!
The NFS server takes its setting from the file ‘/etc/exports’. The format of the file is quite simple, so the entry to export everything under the home directory would be:-
Like NIS, NFS’s export file accepts only IP addresses. To export the same directory to several hosts, use the address/netmask pairing as given above. In brackets, other options specific to the mount may be given. Here I have assigned ‘rw’, which means that the directory is exported with read-write
permissions as by default, NFS exports are read-only.
NFS Client Configuration
On the client machine you can then mount the home directory on the server on every client by modifying the /etc/fstab file on each client like below: -
192.168.1.2:/home /home nfs defaults 0 0
So at boot, the system will mount the entire home directory off the nfs
server and all the user home directories will be available. Make sure that there are no sub-directories under the local /home because after the NFS mount they won’t be visible. You should either delete the /home directory on each client and perhaps even backup /home to something like /home_local :-)
Anyway, reboot the client and try to login again. You will now be authenticated off the NIS server and you
will find yourself in your home directory via NFS. Done!
A word of warning: -
NIS is great for internal small networks, but please be aware that an NIS/NFS solution for network user authentication is not terribly secure. This will probably not be a problem in homes or small offices, but is a major drawback in the enterprise or really large organisations. For secure enterprise information serving, you should look into using LDAP.