Using LDAP to Manage Unix Accounts
Jeff Machols
User management is one of the most tedious tasks in a systems administrator's job. There have been some attempts to centralize user management with NIS and NIS+. NIS fizzled out because of its security holes, and NIS+ is not very straightforward to configure. So, what's the best way to centralize user management in an environment? The answer is looking more and more like LDAP.
LDAP (Lightweight Directory Access Protocol) is quickly emerging as the standard in hierarchical data, such as user and group data. LDAP servers are designed for an "update seldom, access often" scenario. One of the roadblocks LDAP has faced in gaining popularity as a centralized user management system is the effort to get client machines to securely authenticate users. In the past, this required writing custom PAM modules or trying to configure existing ones. However, as major Unix vendors are realizing the potential of LDAP, they are including clients in the operating system.
These built-in clients also contain the PAM libraries for authentication with an LDAP server. These client-side applications are included in the Solaris 8 and 9 distributions, as well as AIX 5L. HP-UX has a free software depot called ldapux that can be found at software.hp.com, and Linux has an RPM called nss_ldap. These clients include built-in libraries, so fears about writing C programs to authenticate or having holes in your security can be put to rest.
Server Considerations
Several LDAP servers are available on the market. Currently, the two predominant servers are OpenLDAP and Sun One Directory Server (formerly iPlanet). If Solaris is your OS for the LDAP server, Sun One Directory Server is the way to go. It is currently bundled with Solaris 9, and version 5.1 is free up to 200,000 entries (each distinguished name in the server is considered an entry). Sun One Directory Server is also available on HP-UX, AIX, and Linux. OpenLDAP is free and can be compiled on most flavors of Unix, but configuration and compilation take a little more effort.
The LDAP community has created an RFC (RFC 2307) to define a schema for Unix to use LDAP as an NIS provider. The schema defines all the previous maps that were available for NIS, so it is aptly named the nis.schema. This schema comes loaded in the standard installation of Sun One Directory Server. If you are using OpenLDAP or another server, be sure the schema is loaded into your server. As part of the nis.schema, the following services can be centralized with LDAP: password, shadow password, groups, and netgroups. Other services, such as DNS, are also available with LDAP, but that is beyond the scope of this article.
The default communications for the LDAP server and clients are clear ASN1 strings. All information is sent in clear text. This is the major problem with NIS, so be sure you don't make this mistake with your LDAP implementation. I recommend using the default communication method during the installation and initial test. Once you have tested the server and the clients, and are comfortable with the configuration, switch to SSL.
When configuring your clients, you will need to specify a search base. This is the point in the directory at which the client starts looking for NIS entries. This functionality allows you to separate Unix user and group accounts from other parts of the directory. For example, you may want to set up a group with a distinguished name (DN) of "ou=unix nis, dc=mydomain, dc=com". You can segregate this more if desired, but all Unix accounts would be under this organizational unit; this DN would be your clients' search base.
Segregating your NIS environment inside the LDAP server will give you two advantages. The first advantage is speed. When you specify the start DN, your clients will not have to search through the entire directory to find the accounts, which will help performance. The second benefit is administrative flexibility. You can give account administrators access to a specific area of the server, instead of to your entire directory. You can have different search bases for different Unix clients. If you do this, note that user accounts will need to be replicated in both search bases to have access to the different clients.
Adding NIS Entries in the LDAP Server
To add a Unix group into LDAP, you will need to create an entry of object class posixGroup. The attribute gidNumber corresponds to the Unix GID number for the group. Since the local and LDAP groups are treated the same, it is important to keep all the gidNumbers in LDAP as well as the local GIDs unique. The Full Name, or cn attribute, is the name of the group. The memberUid attribute correlates to the users who are part if that group. Each user will be an additional attribute in the group's entry. In the example below, users jdoe and scarter are part the admins group:
dn: cn=admins, ou=unix nis, dc=mydomain, dc=com gidNumber: 900 memberUid: jdoe memberUid: scarter objectClass: top objectClass: posixgroup cn: adminsHere are the instructions for adding entries. If you are unsure how to add an entry into an LDAP server, copy the above entry information into a file on the LDAP host and run the following command:
$ ldapadd -D "directory_manager_dn" -w "directory_manager_password" -f filenameYou can assign users to groups in two ways; the first way is described above. Each posixGroup entry will have a list of users. The second method is to assign gidNumbers for each group in the posixAccount entry (described below). These methods can be intermixed but, for consistency, I recommend choosing one method. When you create a new user, you will use the object class posixAccount and shadowAccount along with the standard person object classes. The uid attribute is the user login name, and the uidNumber is the user's Unix uid. The gidNumber attribute lists the groups to which the user belongs. When you specify the password, there are multiple ways to store the ciphered password. For authentication on Unix, you must use the crypt method. This is accomplished by using the {CRYPT} tag in front of the cipher password:
dn: uid=jdoe, ou=unix nis, dc=mydomain, dc=com givenName: John sn: Doe userPassword: {CRYPT}QGxOG7iX3lbLU loginShell: /usr/bin/ksh uidNumber: 343 gidNumber: 900 objectClass: top objectClass: person objectClass: organizationalPerson objectClass: inetorgperson objectClass: posixAccount objectClass: shadowaccount uid: jdoe cn: John Doe homeDirectory: /export/home/jdoeAlong with specifying the password, you can also set password options such as length, minimum characters, expiration, etc. All of the attributes in the NIS schema can be found in RFC2307. With replication and the correct setup, your LDAP environment will be reliable, but there are still some users you should keep out of LDAP. The most obvious is root; this user should always be kept local. I suggest keeping application users local, so even if the network goes down, your applications will still be able to run (assuming they don't need the network). LDAP supports the use of netgroups, so you can control user access to individual servers. The object class is called NisNetGroup and uses the same "triple" notation as NIS. Each entry has three fields: host, user, and domain. If you leave a field blank, it allows complete access. In the entry below, jdoe is in the appuser netgroup for all servers, all domains. The user scarter is in the appuser netgroup only on the server mars, and all users are in the appuser netgroup on the server pluto:
dn: cn=appuser, ou=unix nis, dc=mydomain, dc=com nisNetgroupTriple: ( , jdoe , ) nisNetgroupTriple: ( mars , scarter , ) nisNetgroupTriple: ( pluto , , ) cn: appuser objectClass: top objectClass: nisnetgroupThe passwd command can be used to change the password in the LDAP server. The only change is an extra switch -- the -r option. To change the password for user jdoe:
$ passwd -r ldap jdoeConfiguring the Unix Client Unfortunately, the client setup is different for each version of Unix. There is an effort on the Apache Directory project to document the steps for configuring each client. As each configuration is tested, the documentation will be posted on the Directory Project site. I will use Solaris 9 as an example for the rest of the article. The Solaris 9 clients will run a daemon called /usr/lib/ldap/ldap_cachemgr, which will handle all communication between the client and the LDAP servers. The clients use a configuration profile stored on the servers and periodically update themselves against the profile. This allows you to make a configuration change once that will be populated out to clients automatically. To do this, you need to create an organizational unit for the profile to reside in. Add the following OU:
dn: ou=profile, dc=mydomain, dc=com ObjectClass: top ObjectClass: OrganizationalUnit ou: profileNext, create the profile. This is accomplished by using the ldapclient command built into the OS. This command will create LDIF output that will be added as an entry into the server. The following example will create a profile that will configure the clients to use multiple servers (for replication and failover) and map where in the directory the NIS information will be stored. This command can be run on any Solaris 9 machine regardless of whether it is a server or a client:
$ /usr/sbin/ldapclient genprofile \ -a defaultSearchBase="ou=unix nis,dc=mydomain,dc=com" \ -a serviceSearchDescriptor="passwd: ou=unix nis,dc=mydomain,dc=com" \ -a serviceSearchDescriptor="group: ou=unix nis,dc=mydomain,dc=com" \ -a serviceSearchDescriptor="shadow: ou=unix nis,dc=mydomain,dc=com" \ -a serviceSearchDescriptor="netgroup: ou=unix nis,dc=mydomain,dc=com" \ -a authenticationMethod=simple \ -a credentialLevel=proxy \ -a "defaultServerList=192.168.0.155 192.168.0.156 192.168.10.100" > profile.ldifThe profile.ldif file will contain the entry information. Normally, you should not have to do anything to this file, but you can make changes before adding the entry, if necessary. When you are happy with the profile, add it to the server:
$ ldapadd -D "directory_manager_dn" -w "directory_manager_password" \ -f profile.ldifOnce the profile entry has been added, set up each of the clients to use it. On the client machine, run the ldapclient command with the init option. This command will configure the ldap_cachemgr; it will also copy the /etc/nsswitch.ldap to /etc/nsswitch.conf and start the client in the background:
$ ldapclient -v init -a proxyDN=" directory_manager_dn" \ -w "directory_manager_password" ldapserver_IP_addressIf the client does not start or you encounter other problems, you can add debug flags to get more information. Just add option -d 6 to the command for verbose output:
$ /usr/lib/ldap/ldap_cachemgr -d 6After ldap_cachemgr is up and running, you can test the connection to the server. It will be easier to test if you have at least one entry for each NIS component you are using. To get a list of entries the client finds, run the ldaplist command. You should see all the entries in your search base:
$ ldaplist dn: cn=admins, ou=unix nis, dc=mydomain,dc=com dn: uid=jdoe,ou=unix nis,dc=mydomain,dc=com dn: cn=appuser, ou=unix nis, dc=mydomain,dc=comOnce you get the client talking to the LDAP server, you can begin configuring the OS for user authentication. The first step is to add LDAP as a service in the /etc/nsswitch.conf file. The following nsswitch.conf file will support user authentication, groups, and netgroups in LDAP. If you are not using netgroups, replace the passwd: compat entry with passwd: files ldap and delete the passwd_compat entry:
# # /etc/nsswitch.conf # passwd: compat passwd_compat: ldap group: files ldap # # All other services are unchanged # netgroup: ldapIf you are not using netgroups, you don't need to change the /etc/passwd file. If you are using netgroups, you will need to add the name of the netgroups with access. You will also need to deny other net users. The following snippet can be inserted at the end of the /etc/passwd file to allow users in the netgroup appusers to log onto the server:
+@appusers:x::::: -:x:::::After the entry is added, run the pwconv command to update the /etc/shadow file. You will need to add the LDAP PAM library to the /etc/pam.conf in order to authenticate. The library should already exist in /usr/lib/security; it will be called pam_ldap.so.1:
# # Authentication management # # login service (explicit because of pam_dial_auth) # login auth required pam_authtok_get.so.1 login auth required pam_dhkeys.so.1 login auth required pam_dial_auth.so.1 login auth sufficient pam_unix_auth.so.1 login auth required pam_ldap.so.1 # other auth required pam_authtok_get.so.1 other auth required pam_dhkeys.so.1 other auth sufficient pam_unix_auth.so.1 other auth required pam_ldap.so.1 # passwd auth sufficient pam_passwd_auth.so.1 passwd auth required pam_ldap.so.1 other account requisite pam_roles.so.1 other account required pam_projects.so.1 other account required pam_unix_account.so.1 # # Default definition for Session management # Used when service name is not explicitly mentioned for session # other session required pam_unix_session.so.1 # other password required pam_dhkeys.so.1 other password required pam_authtok_get.so.1 other password required pam_authtok_check.so.1 other password sufficient pam_authtok_store.so.1 other password required pam_ldap.so.1Conclusion
Besides GUIs supplied by the LDAP server, command-line clients also exist. These LDAP clients allow you to add, delete, and modify LDAP entries via the command line and LDIF files. This is useful for scripting or creating custom application to access LDAP.
With the built-in clients, secure connections, and the ability to build GUIs around the server, LDAP has become a viable solution for user management and authentication. Not only does it make it easier to administer users, but LDAP also allows much of the work to be moved to a help desk or level 2 systems administrator support.
Jeff Machols is the Manager of the Unix Administration team for a financial institution and the co-founder of the Apache Directory Project. He can be contacted at: [email protected].