I’ve been working with the Lightweight Directory Access Protocol (LDAP) for 18 years now. Then Microsoft embraced and extended LDAP with Active Directory. Nowadays most companies base all of their authentication and authorization on Active Directory and for good reason. In a Windows-only world it works great. For a mixed-platform environment, it’s a bit more difficult to make work.
I recently worked out how to make Linux systems authenticate against Active Directory using only the LDAP protocol and wanted to share it here for any fellow DevOps/sysaedmins who might want to try it themselves. The goals were to do it with minimum fuss and using the native tools – no third-party apps. I also want to do it solely with LDAP and not have to worry about pointlessly “joining” a Linux host to a domain.
The modern way that Red Hat likes to connect Linux hosts to AD like to do this is to use the SSSD suite of packages, join the host to the Active Directory tree, and talk to AD directly. This seems like a lot of bloat to me when all you need is authentication. Fortunately, you can use the “legacy” means and do it all with LDAP libraries.
Bridging Active Directory and Linux hosts
One way to integrate Linux/UNIX hosts into AD is to add Microsoft Windows Services for UNIX (SFU) schema extensions. This means every AD entry would be defined with common Unix attributes like uid (user id) and gid (group id). These could sometimes get out of sync with the AD attributes and at any rate would require constant updating of the AD records.
Ideally, we won’t depend on Services for UNIX additions in AD and the complexity it brings. Instead, we’ll identify standard AD attributes and map them to Linux/UNIX equivalents. The nss-pam-ldapd package allows us to do this in the /etc/nslcd.conf file, which we’ll see in a minute.
Differences between CentOS 6/AWS and CentOS 7 hosts
One stumbling block has been that Amazon Linux (amzn) uses old, old libraries, based on CentOS 6 packages. The nss-pam-ldapd package which ships with this version of Amazon Linux is version 0.7.5; a version too old to include the mapping functionality we need to avoid using Services for UNIX.
Fortunately, we can remove the amzn version and add an updated one. I have tested one I have found at this link which updates any amzn hosts to the 0.9.8 version of nss-pam-ldapd.
The version of nss-pam-ldapd that ships with CentOS 7 is 0.8.3 and works fine with attribute mapping.
Obtaining the domain’s ObjectSID
The goal of using a directory is consistency. If a user appears in AD, that user will be available to Linux hosts. Also, that user will be treated the same on every directory-equipped server as that user will ideally have the same uid/gid. Without adding Services for UNIX, we need some way to ensure a uid on one host is consistent with the uid on another host. This is done by nss-pam-ldapd by mapping Linux uid/gids to their equivalents in AD, called ObjectSIDs. You need to obtain your AD server’s domain ObjectSID.
The domain ObjectSID can be derived from the user entries in AD. This could be done from Linux using a shell script which converts the binary ObjectSID into the decimal string we need, but it’s a lot of needless work. It is easier to run this query on an AD-equipped server (such as the domain server itself):
dsquery * -filter (samaccountname=mturner) -attr ObjectSID
The sAMAccountname could be any existing user in the AD tree. It doesn’t matter whom.
This will return the following string:
The ObjectSID needed for the uid/gid mapping is highlighted above. The user-specific part of the ObjectSID is at the end of the domain SID and will be used for the uid<-> objectSID mapping.
From a root or sudo terminal session, install nss-pam-ldapd:
yum install nss-pam-ldapd -y
Yum will also pull in nscd as a dependency. nscd is the name service caching daemon, designed to cache responses from the LDAP server and greatly speed up directory services.
Setting Authconfig to use legacy mode
Authconfig assumes you’re using the Red Hat bloatware of SSSD. Instead, you can force only LDAP by editing the /etc/sysconfig/authconfig file and setting this from no to yes:
Add self-signed LDAPS certificate
If you are using a self-signed SSL certificate with your LDAP server to secure your connection, you should save this to your filesystem somewhere. Here I save it as /etc/openldap/cacerts/self-signed.pem:
These are default so no need to change:
Upstream AD server:
Now we tell nslcd where to search for entries. This is done with the base statement:
You can’t talk to AD anonymously so we use a least-privileged AD user specifically for this, the “LDAP Bind” user:
binddn cn=LDAP Bind,CN=Users,DC=example,DC=com
This tells nslcd where to find the users and groups lists that Linux expects to have:
base group OU=Groups,dc=example,dc=com
base passwd CN=Users,dc=example,dc=com
If you’re using a self-signed certificate, specify it:
Now we get to the options specific to Active Directory. Some basic AD settings:
The passwd filter is used to specify who counts as a user vs. who is just another AD object. In the case below, we are looking for both a) someone who is a user, and b) someone who is not a computer:
filter passwd (&(Objectclass=user)(!(objectClass=computer)))
We could also restrict users to a particular group (or more). This is done by specifying the AD code for this and the group name we want to use. Any users who are not in this group are effectively invisible to the system. See the Microsoft documentation for more info on the memberOf attribute.
The below example restricts users to those in the AD group Development (all one line):
filter passwd (&(Objectclass=user)(!(objectClass=computer))(memberOf:1.2.840.1135184.108.40.2061:=cn=Development,OU=Groups,dc=example,dc=com))
Here, we map AD attributes to Linux ones. Note the domain ObjectSID again. We map uid/gid to the sAMAccountName entry.
map passwd uid sAMAccountName
map passwd uidNumber objectSid:S-1-5-21-4483729093-3277648929-7759834922
map passwd gidNumber objectSid:S-1-5-21-4483729093-3277648929-7759834922
map passwd homeDirectory “/home/$sAMAccountName”
map passwd gecos displayName
map passwd loginShell “/bin/bash”
This ensures the display of the uid/gid attributes in an ‘ls -l’ listing properly show the group names. It’s more for convenience and not using it won’t break anything:
filter group (&(|(objectClass=group)(Objectclass=user))(!(objectClass=computer)))
map group gidNumber objectSid:S-1-5-21-4483729093-3277648929-7759834922
map group cn sAMAccountName
Adding the LDAP users/groups into the system’s nameservices
Edit the /etc/nsswitch.conf file and include ldap as a directory source. These sources are consulted in order, so local entries in the /etc/passwd and /etc/shadow files take precedence over ldap entries with the same username:
passwd files ldap
group files ldap
shadow files ldap
Testing it out
You can run the nslcd daemon in debug mode and verify all the pieces are in place:
Now you can run queries on users using the id command from a prompt:
If all is working you should see result similar to the following:
uid=11562(mturner) gid=11562(mturner) groups=11562(mturner),1337(Development)
If you aren’t seeing this AD-added information, check the output of nslcd to see if you are successfully accessing the LDAP server.
You can also query the passwd and group LDAP entries directly:
getent passwd mturner
getent group mturner
Your results will be the AD entries that nslcd has mapped into Linux users and groups.
Setting Linux up to use LDAP for authentication
Now that we’re talking to LDAP and mapping the important attributes, it’s time to turn this on for authentication. This is done using the Linux command, authconfig:
authconfig —enableldapauth —enablemkhomedir —updateall
This will automatically edit the files in /etc/pam.d to add entries for pam_ldap.so. Hopefully you remembered to set FORCELEGACY=yes in /etc/sysconfig/authconfig as noted above, so that you’re only adding LDAP entries and not SSSD entries, too.
The –enablemkhomedir entry uses the pam_mkhomedir.so module to automatically create the users home directory upon first login. Thus, any LDAP user authorized to log into the server (remember the filter passwd line in /etc/nslcd.conf, right?) will have a home directory created upon their first login. There are other options that can be used with pam_mkhomedir so read the man page to see how you can customize this.
Enable SSH to use password authentication
Amazon Linux disables SSH’s password authentication by default. You will be unable to log in using your domain credentials unless you fix this. The default is to allow password authentication, so you simply need to comment out any line in /etc/ssh/sshd_config where “PasswordAuthentication no” is specified:
Restart sshd and you should be able to now log in.
Stop the debug nslcd in favor of the real one
Once you’re done testing, kill the nslcd that may still be running in debug mode:
Starting services and setting them to start automatically
Set the nslcd and nscd daemons to start and run automatically:
CentOS 6 or Amazon Linux:
service nslcd start
service nscd start
chkconfig –level 345 nslcd on
chkconfig –level 345 nscd on
systemctl start nslcd nscd
systemctl enable nslcd nscd
Using AD/LDAP groups for sudo authorization
You can also use AD/LDAP groups to control permissions granted by sudo. For instance, this line grants administrator access to members of the Operations AD group:
#Allows people in group wheel to run all commands
%Operations ALL=(ALL) ALL
That’s pretty much it! Thanks a ton to this page which was very helpful in figuring this out.