Cover V14, i06

Article
Figure 1
Figure 2

jun2005.tar

Migrating to LDAP-Based Naming Service in a Heterogeneous Environment

Kaijun Zhan

Lightweight Directory Access Protocol, or LDAP, is increasingly popular in today's Unix/Linux environment as an option for naming services. Unlike NIS, which is based on a flat namespace, LDAP-based architecture is flexible and scalable. However, the process of seamlessly converting from one naming service to another can be very complicated.

There are several benefits to using LDAP as a primary naming service:

1. LDAP-based namespace allows extensible attributes and objectclasses to describe the data. Thus, data can be more effectively and securely managed through provisioning and automation.

2. LDAP provides security mechanisms to protect the data.

3. LDAP provides security in the transport layer. While NIS is a clear text protocol based on RPC, LDAP is strictly a TCP-based protocol and can leverage SSL (LDAPS) for more secure transmission of the data; additionally, most LDAP products support external authentication methods (such as through GSSAPI).

4. There is one single data repository for various common IT information (such as phone book, hardware, and software inventory, etc.) This is not necessarily a single physical data repository. By chaining and referral, data can be fully distributed while viewed as a single source.

In this article, I'll share some experiences learned from migrating NIS to LDAP in a heterogeneous environment, including Linux, Solaris, HP-UX, and IBM AIX. LDAP itself has various application areas, such as e-commerce and identity management, but only NIS-related issues are discussed. The LDAP server demonstrated in this article is Sun ONE Directory Server 5.2.

Preparation

LDAP-based network naming services are based on RFC2307: "An Approach for Using LDAP as a Network Information Service", where a set of schema are defined. At this time, all major Unix/Linux vendors support LDAP in naming service. For ease of migration, PADL (http://www.padl.com), Sun, HP, and IBM all provide some scripts to help the process. However, in a complex environment, additional works must be done for a successful migration.

The entire migration process may include:

  • Namespace and schema design
  • Physical topology architecture and capacity planning
  • Data consolidation and migration
  • Client conversion and configuration
  • NIS and LDAP coexist
  • Performance consideration
  • Data security, user interface, and administration support

Namespace and Schema

Notice that RFC2307 only covers the following maps:

passwd
group
networks
netgroups
rpc
hosts
services
protocols
Two common NIS maps -- aliases and automount -- are not in the list. As such, some vendors do not support the automount map under LDAP (such as IBM and HP). One option is to use an NIS to LDAP gateway, which uses LDAP as the backend database. For mail aliases, Sendmail supports LDAP as an information lookup not only for mail aliases but also for mail routing and classes, etc. In addition to these common NIS maps, Sun's LDAP implementation also includes Role-Based Access Control maps. Printer configuration is also not listed.

The namespace defines where the data should be located. Since LDAP-based naming service can be hierarchical, it is recommended to map the directory structure to organization and network topology. For medium and large enterprises, a combination of both centralized administration IT and geographical information illustrate this model (Figure 1). We put corporate-level data (such as hosts, networks, and groups) on the top level, and geographically specific data (such as netgroups and automount information) in the branch locations. The reason to put netgroup and automount data into location-based containers is to avoid automount (related to NFS traffic) being referenced over WAN. Because LDAP supports the distributed directory structure, this namespace allows a flexible topology partition. In Figure 1, dotted lines show a possible partition scheme.

Schema

Passwd

LDAP is no longer a simple authentication engine; it supports authorization as well. For large enterprises, centralized management of user identity can be combined with filter-based access control. Our goal is to have centralized user management for the entire enterprise but to have granular control over user access to certain systems and business units. For this purpose, we added a customized objectClass "cdsAccess":

objectClasses: ( 1.3.6.1.4.1.15925.4.1 NAME 'cdsAccess' SUP top 
  STRUCTURAL MAY ( cdsAccessBusinessUnitA $ cdsAccessBusinessUnitB ) 
  X-ORIGIN 'user defined' )
The attributes cdsAccessBusinessUnitA and cdsAccessBusinessUnitB, etc., are defined according to real business organizations. This is not very scalable. An alternative is to use multi-valued attributes. We found multi-valued attributes are difficult to support through the delegated administration.

For example, clients can access the password map via the following definition:

NS_LDAP_SERVICE_SEARCH_DESC=passwd:ou=people,o=cds.com?one?\
  cdsaccessBU=active
Based on the above configuration, the following user will not have access to this client even though this user exists in the same directory as others:

ldapclient% ldaplist -l passwd kzhan
dn: uid=kzhan,ou=people,o=cds.com
        gidNumber: 1000
        homeDirectory: /home/kzhan
        loginShell: /bin/csh
        sn: Zhan
        cn: Kaijun Zhan
        givenName: Kaijun
        mail: kzhan@cds.com
        mailHost: mailhost.cds.com
        uid: kzhan
        objectClass: posixAccount
        objectClass: account
        objectClass: inetOrgPerson
        objectClass: organizationalPerson
        objectClass: person
        objectClass: top
        objectClass: shadowAccount
        objectClass: cdsAccess
        uidNumber: 1000
        title: IT Architect
        cdsAccessBU: nonActive
Netgroups

Netgroups are used for access control for both user logins and NFS shares. In addition to the standard netgroup schema defined in RFC, we added objectclass "cdsNetGroup":

objectClasses: ( 1.3.6.1.4.15925.1.2.2 NAME 'cdsNetGroup' SUP 
  nisnetgroup STRUCTURAL MAY ( cdsChangeApprover $ 
  cdsChangeAuthProc $ cdsChangeJustification
  $ cdsNetworkObjectType $ owner ) X-ORIGIN 'user defined' )
The optional attributes defined in this schema are meta-data to describe the specific netgroup, and some of them are used for properly managing the data. For example, "cdsNetworkObjectType":

attributeTypes: ( 1.3.6.1.4.1.15925.1.1.9 NAME 'cdsNetworkObjectType' 
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 X-ORIGIN 'user defined' )
is a user-defined string to denote whether the netgroup is for USER or HOST. Here are two examples of a netgroup entry:

ldapclient% ldaplist -l netgroup syshosts
dn: cn=syshosts,ou=netgroup,ou=austin,ou=services,o=cds.com
        memberNisNetgroup: syshosts_sub_aaa
        memberNisNetgroup: syshosts_sub_aab
        cdsNetworkObjectType: HOST
        cn: syshosts
        objectClass: top
        objectClass: nisNetgroup
        objectClass: cdsNetGroup

ldapclient% ldaplist -l netgroup sysadmin
dn: cn=sysadmin,ou=netgroup,ou=austin,ou=services,o=cds.com
        nisNetgroupTriple: (-,kzhan,)
        nisNetgroupTriple: (-,bob,)
        cdsNetworkObjectType: USER
        cn: sysadmin
        objectClass: top
        objectClass: nisNetgroup
        objectClass: cdsNetGroup
The function of the user access control part via the netgroup concept can be, and should be, replaced by LDAP filter-based access control, as illustrated in the passwd map.

Automount

The automount map is not part of RFC, and it is the most complicated map among all NIS maps (not conceptually, but implementationally). Currently, there seems to be no standard definition for automount maps, particularly among various Linux flavors.

To serve both Solaris and Linux environments, two entries of auto_master are defined (note that automount maps are placed under location branch):

dn: automountMapName=auto_master,ou=automount,ou=austin, 
  ou=services,o=cds.com
objectClass: top
objectClass: automountMap
objectClass: nisMap
automountMapName: auto_master
nisMapName: auto_master

dn: nisMapName=auto_master_lnx,ou=automount,ou=austin, 
  ou=services,o=cds.com
objectClass: top
objectClass: nisMap
nisMapName: auto_master_lnx
nisMapName: auto.master
This is because Red Hat Linux clients look for nisMapName in the DN while Solaris clients look for automountMapName. Add the suffix "_lnx" to mark that this auto_master map is for Linux clients. (The client configuration for autofs must be changed to reflect this notation, which will be discussed later in detail.)

For SUSE Linux, the syntax is also different from Red Hat Linux. As such, the following entry of auto_master for SUSE Linux might be helpful (but not mandatory as explained in the auto_home section):

dn: nisMapName=auto_master_lnx_suse,ou=automount,ou=austin, 
  ou=Services,o=cds.com
nisMapName: auto_master_lnx_suse
objectClass: top
objectClass: nisMap
Regarding automount home entries in the directory, assume the user login is "kzhan" and the home directory server is called "homeserv". For Solaris clients, auto_home is defined by:

dn: automountkey=/home,automountMapName=auto_master,ou=automount, 
  ou=austin,ou=services,o=cds.com
objectClass: top
objectClass: automount
automountKey: /home
automountInformation: auto_home -intr,nobrowse
This tells the mount information for /home is located in the map auto_home:

dn: automountkey=kzhan,automountMapName=auto_home,ou=automount, 
  ou=austin,ou=services,o=cds.com
objectClass: top
objectClass: automount
objectClass: nisObject
automountKey: kzhan
cn: kzhan
nisMapName: auto_home
nisMapEntry: homeserv:/export/home/kzhan
automountInformation: homeserv:/export/home/kzhan
For Red Hat Linux clients, the following entry instructs the autofs daemon to look for auto_home information with attribute nisMapEntry:

dn: cn=/home,nisMapName=auto_master_lnx,
  ou=automount,ou=austin, ou=services,o=cds.com
nisMapName: auto_master_lnx
objectClass: nisObject
objectClass: top
nisMapEntry: ldap:automountMapName=auto_home,ou=automount, 
  ou=austin,ou=services,o=cds.com -intr,nobrowse
SUSE Linux is almost identical to Red Hat Linux, except that the nisMapEntry attribute has a different syntax (without ":"):

nisMapEntry: ldap automountMapName=auto_home,
  ou=automount,ou=austin,ou=services,o=cds.com 
  -intr,nobrowse
This also can be changed on the client side by modifying /etc/init.d/autofs script if you do not want to have complicated server-side definitions.

Aliases

ObjectClass mailGroup is used for aliases. Membership of an alias is defined by attribute "mgrpRFC822MailMember":

ldapclient% ldaplist -l aliases sysmgt
dn: cn=sysmgt,ou=aliases,ou=corp,ou=services,o=cds.com
        cn: sysmgt
        objectClass: top
        objectClass: mailGroup
        mail: sysmgt
        mgrpRFC822MailMember: kzhan
        mgrpRFC822MailMember: bob
This will work under Sun Solaris 8 and 9 with a vendor-supplied Sendmail package. If you compile Sendmail by yourself (or Linux sendmail), add the following option in sendmail.cf:

O AliasFile=/etc/mail/aliases, ldap:-k \
  (&(objectClass=mailGroup)(mail=%0)) \
  -v mgrpRFC822MailMember
Client Configuration

As of this writing, the following platforms have been successfully converted to full LDAP-based naming service:

  • Red Hat Linux 7.2, 7.3, 8, 9, Enterprise Linux 2.1, 3.0, AS2.1
  • SUSE Linux 9
  • Solaris 8 (kernel level 21 or above)
  • Solaris 9

For these platforms, automount is not supported:

  • HP-UX 11
  • IBM AIX 4, 5
  • Sun Solaris 7 and Solaris 8 without proper patches

To have a fully functional netgroup map, make the following clarifications:

  • For Solaris 8 and 9, the login access part of netgroup must be properly patched (108993-37 for Solaris 8, and 112960-18 for Solaris 9). The NFS share part of netgroup works natively, provided that the host name matches. In the netgroup definition, "host.cds.com" is different from "HOST.cds.com" or just "host". Host names are case sensitive (though neither LDAP nor DNS is case sensitive).
  • For Linux, the NFS share part of netgroup works. For the login access part, EE 3.0 and above works. However, for versions below that, the pam_list module is needed. This module is installed by default but not enabled. To enable pam_list, add the following line in /etc/pam.d/system-auth:

    account required pam_listfile.so item=user sense=allow \
      onerr=fail file=/etc/security/validusers
    

Using filter-based access control for login is much simpler.

Before converting any clients, we need to create profiles. A profile is a collection of configuration parameters so that we can call a profile name to get all configuration data. Solaris uses "ldapclient(1M)" to configure the LDAP client by calling a profile, and Linux simply takes the content of a profile as /etc/ldap.conf. Let's construct a profile called "default":

ldapclient% ldapsearch -h ldaphost -L -b ou=profile,o=cds.com cn=default
dn: cn=default,ou=profile,o=cds.com
serviceSearchDescriptor: services:ou=services,ou=corp, 
  ou=services,o=cds.com?one
serviceSearchDescriptor: passwd:ou=people,o=cds.com?one? 
  cdsaccessBU=active
serviceSearchDescriptor: shadow:ou=people,o=cds.com?one? 
  cdsaccessBU=active
serviceSearchDescriptor: aliases:ou=aliases,ou=corp,ou=services, 
  o=cds.com?one
serviceSearchDescriptor: hosts:ou=hosts,ou=corp,ou=services, 
  o=cds.com?one
serviceSearchDescriptor: group:ou=group,ou=corp,ou=services, 
  o=cds.com?one
serviceSearchDescriptor: networks:ou=networks,ou=corp, 
  ou=services,o=cds.com?one
serviceSearchDescriptor: rpc:ou=rpc,ou=corp,ou=services,o=cds.com?one
serviceSearchDescriptor: netmasks:ou=netmasks,ou=corp, 
  ou=services,o=cds.com?one
serviceSearchDescriptor: netgroup:ou=netgroup,ou=austin, 
  ou=services,o=cds.com?one
serviceSearchDescriptor: automount:ou=automount,ou=austin, 
  ou=services,o=cds.com?sub
serviceSearchDescriptor: protocols:ou=protocols,ou=corp, 
  ou=services,o=cds.com?one
defaultServerList: 192.168.1.1 192.168.2.1
authenticationMethod: simple
followReferrals: TRUE
defaultSearchScope: sub
searchTimeLimit: 30
profileTTL: 120
cn: default
credentialLevel: proxy
bindTimeLimit: 10
defaultSearchBase: o=cds.com
preferredServerList: 192.168.1.1 192.168.2.1
description: default LDAP profile
objectClass: top
objectClass: DUAConfigProfile
objectClass: cdsdirobjectinfo
To convert a Solaris 8 client with the profile "default", use:

ldapclient# ldapclient  -v -P default -d cds.com -D \
  "cn=ldapbind,ou=profile,o=cds.com" -w bindpw 192.168.1.1
At this point, /etc/nsswitch.conf should be changed because "ldap" is being added as one naming service option. We can manually edit it to fit our needs. Also, a process ldap_cachemgr is started:

ldapclient# ps -ef | grep ldap_cachemgr
    root   212    1  0   May 28 ?    64:42 /usr/lib/ldap/ldap_cachemgr
With slightly different syntax, use the following command to convert a Solaris 9 client:

ldapclient# ldapclient init -a proxyDn=cn=ldapbind,ou=profile,o=cds.com \
  -a profilename=default -a proxypassword=bindpw 192.168.1.1
For Solaris 7, there is no automatic conversion utility. Manually edit /etc/ldap.conf, /etc/pam.conf, and /etc/nsswitch.conf files. Additionally, if you don't have nss_ldap and pam_ldap modules, you must compile them. See http://www.padl.com for details.

The Linux client does not have a conversion utility. Here are the steps:

1. Create /etc/ldap.conf, similar to the one defined in profile "default":

ldap-linux% cat /etc/ldap.conf
BINDDN cn=ldapbind,ou=profile,o=cds.com
BINDPW bindpw
HOST 192.168.1.1 192.168.2.1
BASE o=cds.com
SCOPE sub
TIMELIMIT 30
BIND_TIMELIMIT 10
REFERRALS TRUE
NSS_BASE_PASSWD ou=people,o=cds.com?one?cdsaccessBU=active
NSS_BASE_SHADOW ou=people,o=cds.com?one?cdsaccessBU=active
NSS_BASE_NETWORKS ou=networks,ou=corp,ou=services,o=cds.com?one
NSS_BASE_RPC ou=rpc,ou=corp,ou=services,o=cds.com?one
NSS_BASE_PROTOCOLS ou=protocols,ou=corp,ou=services,o=cds.com?sub
NSS_BASE_NETMASKS ou=netmasks,ou=corp,ou=services,o=cds.com?one
NSS_BASE_HOSTS ou=hosts,ou=corp,ou=services,o=cds.com?one
NSS_BASE_SERVICES ou=services,ou=corp,ou=services,o=cds.com?one
NSS_BASE_GROUP ou=group,ou=corp,ou=services,o=cds.com?one
NSS_BASE_ALIASES ou=aliases,ou=corp,ou=services,o=cds.com?one
NSS_BASE_NETGROUP ou=netgroup,ou=austin,ou=services,o=cds.com?one
NSS_BASE_AUTOMOUNT ou=automount,ou=austin,ou=services,o=cds.com?sub
2. Make a symbolic link from /etc/openldap/ldap.conf to /etc/ldap.conf; doing so ensures autofs finds the right ldap.conf file.

3. Modify /etc/init.d/autofs so that the line

/usr/lib/autofs/autofs-ldap-auto-master 2> /dev/null
is changed to:

/usr/lib/autofs/autofs-ldap-auto-master auto_master_lnx 2>/dev/null
For SUSE Linux, then use:

/usr/lib/autofs/autofs-ldap-auto-master auto_master_lnx_suse
or:

/usr/lib/autofs/autofs-ldap-auto-master auto_master_lnx|sed -e 's/:/ /'
to replace ":" with <space> in LDAP lookup syntax}.

4. Modify /etc/nsswitch.conf to reference LDAP.

5. Remove NIS configuration from /etc/sysconfig/network.

6. Restart autofs. Upon restart, you should see ldap is being referenced by autofs:

ldap-linux% /etc/init.d/autofs status | grep auto_home
/usr/sbin/automount /home ldap automountMapName=auto_home, \
  ou=automount,ou=austin,ou=services,o=cds.com -intr,hard \
  udp,rsize=8192,wsize=8192
In early versions of Red Hat Linux, systems without Naming Service Cache Daemon (nscd) running will not recognize Unix groups with large number of members. nscd will also have a significant impact on performance and must be enabled for proper LDAP functions (it is off by default installation). Furthermore, if you have a wild-card definition in automount maps, then it is "*" for Solaris clients and "/" for Linux clients. Thus, these maps must be created twice to meet both worlds.

For HP-UX 11.x, necessary patches must be installed first. The patch list is available at:

http://docs.hp.com/en/J4269-90042/J4269-90042.pdf
Then install the LDAP client depot file (LDAPUxClient subproduct, J4269AA, available at:

http://software.hp.com
Upon completion, configure the client:

ldapclient-hp# grep -v "^#" /etc/opt/ldapux/ldapux_client.conf
[profile]
Service: NSS
LDAP_HOSTPORT="192.168.1.1:389"
PROFILE_ENTRY_DN="cn=default,ou=profile,o=cds.com"
PROGRAM="/opt/ldapux/config/create_profile_cache"
Now we can download the profile:

ldapclient-hp# cd /opt/ldapux/config ; ./get_profile_entry -s nss
HP-UX provides ldapclientd to manage the LDAP service. Its configuration file is /etc/opt/ldapux/ldapclientd.conf. As mentioned earlier, HP-UX does not support automount maps.

The Transition: Coexistence of LDAP and NIS

In large enterprises, the transition from NIS to LDAP takes time, and legacy NIS clients must stay. There are several options for this "mixed" environment.

One option is to export the LDAP data via text files and then build NIS maps. However, this process requires scripting and coordination, and it is very labor-intensive if there are multiple NIS domains. For our purposes, we choose to use the NIS-to-LDAP gateway, a product that helps in this scenario. HP, Sun, and PADL all provide the gateway tool. Because we use the Sun Directory Server, the Sun NIS gateway was deployed.

The gateway is not only for systems depending on NIS, but also for systems that can partially use LDAP but require NIS for automount map resolution, such as Solaris 7, HP-UX 11.x, and IBM 4.x. Figure 2 demonstrates such an environment.

The gateway usually resides on the same LDAP system (but it doesn't have to). For an NIS gateway on a Sun system (Solaris 9, release 12/03 or later), there are two files that must be configured: /etc/default/ypserv and /var/yp/NISLDAPmapping. The first file is for general configuration, such as binding account, search timeout value, and limit, etc. The second file defines how the NIS map should be constructed from LDAP. For example, the following defines the "group" map:

nisLDAPobjectDN group: \
                        ou=group,ou=corp,ou=services,?one? \
                        objectClass=posixGroup:
nisLDAPattributeFromField group.byname: \
                        dn=("cn=%s,", rf_key ), \
                        gidNumber=gid
nisLDAPattributeFromField group.bygid: \
                        dn=("cn=%s,", name ), \
                        gidNumber=rf_key
nisLDAPattributeFromField group: \
                        cn=name, \
                        userPassword=("{crypt}%s",passwd), \
                        (memberUid)=(users, ",")
After all proper configurations, start the ypserv daemon:

ldap-nis-gw# cd  /usr/lib/netsvc/yp
ldap-nis-gw# ./ypserv -dv -r
ldap-nis-gw# ./ypstart
After the NIS gateway is running properly, additional NIS slaves (with the gateway server being the master) can be added. Setting up an NIS slave is identical to the normal NIS environment. However, one difference is that the NIS gateway no longer has a "make" process to push maps to slaves, so you must either add cronjobs on the master or slave servers.

Another aspect of LDAP migration is backward (to NIS) compatibility. There are applications, scripts, or processes, depending on "yp-" commands, such as "ypcat" and "ypmatch". In LDAP, these commands no longer exist. Similar utilities, such as "getent(1)" or "ldaplist(1)", should be used. However, we also developed Perl scripts for yp commands allowing users to migrate their utilities to native LDAP commands:

ldapclient% file /usr/bin/ypwhich /usr/bin/ypmatch
/usr/bin/ypwhich:       executable /usr/bin/perl script
/usr/bin/ypmatch:       executable /usr/bin/perl script
ldapclient% ypwhich
ldap servers: 192.168.1.1 192.168.2.1
ldapclient% ypmatch kzhan passwd
kzhan:x:1000:1000:Kaijun Zhan:/home/kzhan:/bin/csh
Capacity Planning and Performance Tuning

Sun ONE Directory Server 5.2 allows replication based on database and attributes (partial replication). We decided to have two main databases -- one for people-related data, and one for the rest. This physical database is different from logical partition of the directory structure. We choose one single partition for the entire directory. In setting up servers, important parameters are dbcachesize, cachememsize, allidsthreshold, and cachesize. Allidsthreshold should be carefully chosen, as modification of this parameter requires a database rebuild. We recommend allidsthreshold to be close to the number of entries of the largest NIS map (but no more than 50,000, according to Sun's recommendation). Sun has a document to estimate server parameters, which require the total number of entries in the database. As a starting point, this number can be roughly equal to the total number of entries in all NIS maps, then make adjustments later.

Some critical factors that will affect client performance:

  • Server architecture -- The number of databases, how these databases are replicated, and whether clients access the LDAP servers directly or via proxy. Proxy allows administrators to adjust the weight of LDAP servers in a pool based on each server's performance. It can be self-adaptive in theory.
  • Number of Access Control Lists (ACLs) -- The ACLs are for data protection and provide one advantage of LDAP over NIS. However, ACLs will degrade performance significantly. For every client search, a big portion of operation is spent on ACL evaluation and these ACLs have to be evaluated on the fly every time. (We have cases where about 50% of CPU time is spent on ACL evaluation.) The rule of thumb is to put ACLs as close to the data (being protected) as possible. For example, if you have an ACL to deny write permission to uid=kzhan,ou=people,o=cds.com, an ACL can be placed at o=cds.com or at ou=people,o=cds.com. For best performance, ACL should be placed at uid=kzhan,ou=people,o=cds.com.
  • Client behavior -- These include both system calls (such as getpwuid()) or utilities such as "ldapsearch". Optimize the searches as much as possible. This is particularly true when developing home-grown scripts and Web interfaces.
  • Indexing -- Make sure all search indices are constructed. In an NIS environment (unlike an e-business Web arena), a lot of system calls depend on vlvIndex (virtual list view), a browsing index. These browsing indices are often overlooked and therefore cause major performance impact.

RFC2307 lists about two dozens or so affected library functions in NIS operations. These functions are used like the ls command. The corresponding filters for these library functions are defined in the RFC. For example, if "getpwent()" is called, then the associated filter is "(objectClass=posixAccount)" so a vlvindex satisfying this filter must be in place. To do so, load the following LDIF file via ldapmodify:

dn: cn=cds.com_passwd_vlv_index,cn=people,cn=ldbm 
  database,cn=plugins,cn=config
objectClass: top
objectClass: vlvSearch
cn: cds.com_passwd_vlv_index
vlvBase: ou=people,o=cds.com
vlvScope: 1
vlvFilter: (objectClass=posixAccount)
aci: (target="ldap:///cn=cds.com_passwd_vlv_index,cn=people,cn=ldbm 
  database,cn=plugins,cn=config")(targetattr="*")(version 3.0; acl 
  "Config";allow(read,search,compare)userdn="ldap:///anyone";)
numSubordinates: 1

dn: cn=cds.com.getpwent,cn=cds.com_passwd_vlv_index,cn=people,cn=ldbm
  database,cn=plugins,cn=config
cn: cds.com.getpwent
vlvSort: cn uid
objectClass: top
objectClass: vlvIndex
In this LDIF file, the vlvBase and vlvScope must match the client configuration (check /etc/ldap.conf). Now shut down the LDAP server and build the vlvindex:

ldapserver# ./vlvindex -n people -T cds.com.getpwent
where the argument in "-n" denotes the database name. We must create the vlvIndex for all possible library calls.

To make sure you have all the indices, check the lines in the LDAP server access log file with "notes=U" and lines similar to:

[30/Jun/2004:12:31:48 -0800] - WARNING<20805> - Backend Database \
  - conn=3284361 op=1 msgId=2 -  search is not indexed
in the error log file. If these lines exist, then grep conn=3284361 <access-log-file> to find out what is missing.

The access log also contains rich information for troubleshooting. Even if there is no index problem, there is still a chance the search is slow. Try to analyze the access log with etime (elapsed time for each operation) to see which are the longest searches. Ideally, etime should be 0.

Security and Data Access Control

In a large deployment, LDAP data maintenance is likely divided among various groups. We use ACL. Though ACL can be very sophisticated, it can also slow down the performance. Dynamic ACL can help reduce the number of ACLs. For example, ou=austin branch gives ALL permission to Unix administrators at the Austin office, and ou=newyork is for the New York office. Instead of creating two static ACLs, try to use a certain syntax, such as a Unix admin group called "${location}" and a single ACL would be:

aci: (targetattr="*")(target="ldap:///($dn),ou=services,o=cds.com") 
  (version 3.0; acl "Site Admin Access"; allow (all) 
  groupdn="ldap:///cn=site_admins,[$dn],ou=admin_accounts, 
  ou=groups,o=cds.com";)
Filter-based access control is not only for security but also effective to limit the data needed for the client.

Conclusion

In this article, I've outlined steps in the migration of NIS to LDAP. The entire process is complicated. However, if planned carefully, the migration will be successful and corporations will see the benefits of the migration.

Kaijun Zhan has a PhD in mathematics and has been a sys admin since 1992. He is currently the IT Architect at Cadence Design Systems. His interests include architecture design in DNS, NIS, Messaging, LDAP, and security. He can be contacted at: kzhan@cadence.com.