This guide continues from the previous article in the series.
Step 3 - Setting up LDAP integration with NSS on a legacy system
Prerequisites for this step
- A *NIX system that will be integrated with Active Directory using LDAP connectors for NSS and PAM. In this example we will use a CentOS 6.8 system with the nss-pam-ldapd packages from the standard package repository on this platform.
- A service account in Active Directory that will be used to authenticate to the ldap proxy. No UNIX profile is necessary. In this example the account is named 'svc-ldapauth'
Install required packages (dependant on the target operating system, in our case on CentOS 6.8)
# sudo yum install nss-pam-ldapd oddjob-mkhomedir openldap-clients
These packages provide the following functions:
- nss-pam-ldapd is a package in the RHEL6 repository that provides RFC2307 LDAP integration for NSS and PAM (identities and authentication)
- oddjob-mkhomedir provides automatic creation of home directories on user login
- openldap-clients provides the ldapsearch binary that we will use for debugging purposes (and is thus not required on a production system, once the configuration has been determined).
Configure oddjob-mkhomedir to automatically create home directories on user login
# sudo service messagebus start
# sudo chkconfig messagebus on
# sudo authconfig --enablemkhomedir --update
Test that network communication works to the ldap proxy, and that the ldap proxy provides valid RFC2307 responses when querying for a UNIX profile for a valid user ('dwirth' in this example, as retrieved at the end of step 2).
# ldapsearch -h ldapproxy.centrify.vms -b dc=centrify,dc=vms -D email@example.com -W '(&(objectClass=posixAccount)(uid=dwirth))'
Note that -h is used to specify the ldap proxy server's hostname, -b the search base (in this case the distinguished name of the Active Directory domain), -D a valid Active Directory account for which we know the password (does not need to have a UNIX profile), -W indicates that we will supply the password on a password prompt in order to perform an LDAP simple bind (alternatively, use -w followed by the password in plain text for debugging), and '(&(objectClass=posixAccount)(uid=dwirth))' is the search filter to search for objects that are both of objectClass posixAccount (RFC2307 UNIX user profiles) and with login name 'dwirth' (uid is the login name attribute in the RFC2307 schema).
This command should return a valid UNIX profile as it is defined in the Centrify Zone.
Now that we know we have a valid user profile that is served by the Centrify ldap proxy, we can start configuring NSS and PAM modules to use the ldap proxy.
Configure NSS integration
Configure the daemon that provides integration with Name Server Switch, in our example environment (RHEL/CentOS 6.x) this is 'nslcd', that has its configuration file in /etc/nslcd.conf
Set the following options in /etc/nslcd.conf
# Mappings for RFC2307 Centrify LDAP Proxy
filter passwd (objectClass=posixAccount)
filter group (objectClass=posixGroup)
# user and group id for daemon process
# LDAP server information
The above parameter and their values are explained as follows:
'filter passwd' and 'filter group' define the objectClasses to query for identities (the provided values follow RFC2307)
'scope sub' is required to search the subtree located under 'base'
'uid' and 'gid' are used for isolation of the nslcd process; don't change these values from their defaults.
'uri' defines the hostname of the ldap proxy. This name needs to be resolvable through DNS, and should match the subject of the X.509 certificate that will be used when the LDAP proxy is secured at a later stage.
'base' defines the search base, and can be set to the base container or OU under which the Centrify zones are located, that contain the UNIX profiles. In this example this is the zones container in the centrify organizational unit, located in the root of the centrify.vms domain.
'binddn' denotes the identity of the service account that will bind to the ldap proxy. We don't use DN notation, as both AD and the Centrify LDAP proxy accept the much simpler '@' notation.
'bindpw' denotes the password for this account in plain text.
Start nslcd.conf & add to automatic system startup
# sudo service nslcd start
# sudo chkconfig nslcd on
Enable integration of the NSS LDAP daemon (nslcd) in /etc/nsswitch.conf
passwd: ldap files
shadow: ldap files
group: ldap files
Test nsswitch.conf integration with nslcd
# getent -s ldap passwd
# getent -s ldap shadow
# getent -s ldap group
NOTE that the user's common name in Active Directory will be shown in the password hash (2nd field) of the output of the passwd map, as the Centrify LDAP proxy is configured by default to use this mapping (line 'posixAccount.userPassword: cn' in /etc/centrifydc/openldap/rfc2307.map ). This is expected and poses no issues.
NOTE further that In our example, getent group does not show any output.
To find out why this is the case, we need to look at the ldap proxy log (/var/log/ldapproxy.log) after running 'getent -s ldap group' on the legacy system.
Here's the relevant snippet from the log:
slapd: 57edfd4d conn=1004 op=21 SRCH base="cn=zones,ou=centrify,dc=centrify,dc=vms" scope=2 deref=0 filter="(objectClass=posixGroup)"
slapd: 57edfd4d conn=1004 op=21 SRCH attr=cn userPassword memberUid gidNumber uniqueMember
slapd: cdcLdapSearch :No such attribute (cdcRC=8), errSystem=Ldap, errCode=16, errString=No such attribute
From the first two lines of the above output, we can see that the nslcd daemon launched a query with ldap filter '(objectClass=posixGroup)', and asks to return attributes 'cn userPassword memberUid gidNumber uniqueMember'
When the ldap proxy does not recognize any requested return attribute among a list of attributes, it will refuse to return results for all attributes.
To fix this, we need to find out which attribute is causing this issue. Manually replicate the ldap query, but request a single return attribute at a time, until we find all the unsupported return attributes:
# ldapsearch -h ldapproxy.centrify.vms -b cn=zones,dc=centrify,dc=centrify,dc=vms -D firstname.lastname@example.org -W '(objectClass=posixGroup)' cn
# ldapsearch -h ldapproxy.centrify.vms -b cn=zones,dc=centrify,dc=centrify,dc=vms -D email@example.com -W '(objectClass=posixGroup)' uniqueMember
Both the query for 'userPassword' and 'uniqueMember' fail. After some research, we can find that userPassword is an optional attribute of the posixGroup class in RFC2307, and that 'uniqueMember' is equivalent to memberUid in DN notation, part of RFC2307bis.
So it seems our nslcd daemon tries to be clever and query attributes for both RFC2307 and RFC2307bis at the same time, in the hope it gets at least one result back. Unfortunately, this breaks our Centrify LDAP proxy, and we will need to prevent this from happening.
Fortunately, the nslcd configuration allows mapping of certain attributes to other values; as we use neither uniqueMember nor userPassword, we can safely map them to 'memberUid' and 'cn' attributes respectively, by adding the following lines to /etc/nslcd.conf :
map group uniqueMember memberUid
map group userPassword cn
To apply the changes, restart the nslcd serice
# sudo service nslcd restart
Check whether group identities are now properly retrieved
# getent -s ldap group
Now validate that secondary group membership is properly resolved for a user that has membership to secondary groups (in this example for user 'tetsu')
# id tetsu
Run the command on the proxy server and compare the output. They should be identical on proxy server and on the legacy platform using NSS ldap integration
In the lab environment, this is not the case. Only the primary group shows up as group membership in the output of the 'id' command.
Let's look at the ldap proxy logs to find out why. After the 'normal' lookups by the nslcd daemon, it performs a query to find the secondary group membership for user 'tetsu':
slapd: 57eee4bb conn=1009 op=91 SRCH base="ou=centrify,dc=centrify,dc=vms" scope=2 deref=0 filter="(&(objectClass=posixGroup)(|(memberUid=tetsu)(memberUid=cn=Tetsu Ishii,ou=Contractors,ou=Users,ou=Staff,dc=centrify,dc=vms)))"
This query seems to fail due to 'Bad search filter'. Unfortunately, it seems that the nss-pam-ldap package in RHEL/CentOS 6.x will use a single query that it expects to return results regardless of RFC2307 or RFC2307bis schema usage on the server. On most LDAP servers this will work, but the Centrify LDAP proxy does not handle LDAP queries with a search filters of type '(&(a)(|(b)(c))' (which translates to: return ldap objects for which both conditions (a and b) are true or (a and c) are true).
As a result, we need to give up on getting secondary group membership for the nslcd package as it is used in RHEL/CentOS 6.8; this limitation is unlikely to be run into in practice, as systems running RHEL/CentOS 6.x can be joined with the native Centrify agent.
The LDAP connectors for NSS and PAM on legacy platforms, are not very likely to use this same type of query that combines a search for both RFC2307 and RFC2307bis attribute values without having some sort of toggle to disable this behaviour.
In the final part of the article series, integration with PAM (authentication) will be detailed, as well as securing the solution.
Step 4 - Setting up LDAP integration with PAM on a legacy system
With users and groups now visible in NSS, we can proceed to configuring the PAM module for authentication of these users.
Configure PAM integration, by configuring the module that provides integration with PAM, in our example this is 'pam_ldap', which has its configuration file in /etc/pam_ldap.conf
Configure /etc/pam_ldap.conf with the following lines
NOTES on the above configuration
- The explanation for the defined values is, safe for a different parameter for defining the server, pretty much the same to the explanation for nslcd.conf ('host' vs 'uri')
- We purposely define the base distinguished name more broad than for the NSS daemon (nslcd.conf), as we want to differentiate between queries launched by nslcd and by pam_ldap.conf while we are in the troubleshooting stage.
- Although defined with a value identical to the value of 'base', the nss_base_passwd parameter needs to be specified, else the (objectClass=posixAccount) pam_filter is included twice in the query (bug in pam_ldap?). This prevents Centrify LDAP proxy from providing results (a limitation of the type of ldap queries that Centrify LDAP proxy can handle).
Configure the PAM stack to use the pam_ldap module
# sudo authconfig --update --enableldapauth
Now try to log in (ssh or console) to the legacy server with a valid user profile (in our case 'dwirth').
# ssh firstname.lastname@example.org
If you are denied access (like we are in this example environment), go to the ldap proxy to analyze the log files by searching for the base DN that we query for with the pam_ldap module.
For example, we get the following output:
slapd: 57ee06f7 conn=1033 op=1 SRCH base="ou=centrify,dc=centrify,dc=vms" scope=2 deref=0 filter="(&(objectClass=posixAccount)(uid=dwirth))"
slapd: 57ee06f7 conn=1033 op=1 SRCH attr=host authorizedService shadowExpire shadowFlag shadowInactive shadowLastChange shadowMax shadowMin shadowWarning uidNumber
The above query fails due to unrecognized return attributes;
Let's run the query manually using ldapsearch for each requested return attribute to find out which return attribute prevent the query from working:
# ldapsearch -h ldapproxy.centrify.vms -b cn=zones,dc=centrify,dc=centrify,dc=vms -D email@example.com -W '(&(objectClass=posixAccount)(uid=dwirth))' host
# ldapsearch -h ldapproxy.centrify.vms -b cn=zones,dc=centrify,dc=centrify,dc=vms -D firstname.lastname@example.org -W '(&(objectClass=posixAccount)(uid=dwirth))' uidNumber
Running the above queries show that the 'host' and 'authorizedService' attributes are not recognised. Unfortunately, setting the parameters 'pam_check_host_attr' and 'pam_check_service_attr' in /etc/pam_ldap.conf to 'no' don't seem to change the query behaviour, regardless of what the description of these parameters implies.
As we cannot change the behaviour of pam_ldap, we need instead to map these attributes to something valid, on the ldap proxy.
Add the following lines in /etc/centrifydc/openldap/rfc2307.map on the server hosting the Centrify LDAP proxy, to map these attributes to the uidNumber value instead (should be harmless, as host and authorizedService values supposedly are not used by pam_ldap in the default configuration):
Restart the Centrify ldap proxy to apply the configuration changes
# dzdo service centrify-ldapproxy restart
Retry the previously failing ldap queries to validate that the mapping works.
Now that these queries work, try to log in to the legacy system through SSH or console using a unix user that the LDAP proxy provides the profile for
# ssh email@example.com
Your LDAP password will expire in 4294967257 days.
Creating home directory for dwirth.
In the final part of the series, securing the LDAP proxy server and ldap client is detailed, as well as a recap of the advantages that this type of agentless integration provides compared to alternative options.