What’s an LDAP Proxy? When, how and why should you use one? These questions and more will be answered here.
Let’s start with the basics. What is it?
Centrify Server Suite agents (Standard or Enterprise) include an optional module called LDAP Proxy. This module consists of both a LDAP client and server (slapd) that works alongside the core adclient agent to provide a RFC2307 compliant LDAP interface in front of Active Directory. This is most commonly used in Hadoop environments to facilitate ldap/s communications during the security wizard as well as on-going user sync and authentication functions for ecosystem tools. It’s also very popular in storage device integrations that need to lookup uid/gid information for Active Directory users. But generally, anything capable of talking LDAP that wants clean zone data instead of complex AD queries can take advantage of this tool.
Why do we need it in the first place?
The simple answer is: even if these tools are capable of talking to Active Directory, most, if not all, expect to find POSIX data stored within the user and group objects they are targeting. Most include complex mapping sheets forcing admins to guess which AD attributes might be targeted. However, even if you know the correct attribute name, it’s more than likely the values of those attributes won’t be populated as expected.
There are several Active Directory bridging solutions that either have existed at one time or still remain but one fact has remained fairly consistent among all of our designs: mapping data is stored in dedicated serviceConnectionPoint objects, not the user or group objects they are associated with. So is true with Centrify. What is different about us, is we had the foresight to know this might cause issues for some integrations and created a proxy to make that problem go away.
So what in the world is a serviceConnectionPoint object and what does that really mean?
In order for an Active Directory user to be authenticated by a Linux/Unix/Mac domain client using a Centrify agent (or any other), the user will first need basic POSIX properties associated with these operating systems: a user ID (uid), a user ID number (uidNumber), primary group number (gidNumber), home directory (unixHomeDirectory), and shell (loginShell). All of these attributes have been part of the standard Active Directory schema since Windows 2003 R2 so the good news is you don’t have to modify or customize your schema in any way to integrate non-Windows systems into Active Directory.
However, from a product design perspective, you have a few options. We could populate the target user or group object using the standard attributes with the appropriate values. However, if we do that, you’re stuck with that same mapping value across all systems that user may come in contact with. You also have to delegate full write access to the user or group object to administrators who may only need access to manage mappings. There are other cons here as well but the take away here is putting everything into a single object makes for a very limited product.
So we, and every other vendor to my knowledge, took the other route. We created a dedicated organizational unit structure and, for each mapping, used built-in serviceConnectionPoint objects to store the mapping details along with a pointer associating it to the securityID of the intended user or group (in this forest, that forest, wherever the user or group may live as long as there’s a trust). When the agent looks up the user, it’s programmed to look at the serviceConnectionPoint object for user details and follows the securityID trail to authenticate against the real user object. This data is all cached so it’s very efficient and very flexible when it comes to multiple mappings, delegation granularity and all the rest.
Problem solved, right? World peace is established, all programs everywhere can simply use PAM to talk to adclient and always be served up fresh data in exactly the format they need without worrying about the backend plumbing. Unfortunately, not…
The reality is most Unix based programs and appliances simply don’t have the experience integrating with Active Directory and even if they did, they probably wouldn’t design their integrations around what are mostly third-party designs. That leaves neatly secured systems in a tough spot when it comes to making all of this work together. That’s where the LDAP Proxy comes in.
Now, instead of pointing the app to Active Directory to look-up Unix details (and failing), as long as they include a compliant LDAP option, we can take all of the hard work away. App points to the proxy, makes its query, is given clean data from adclient cache, and we’re back to world peace status. Crack open a beer, kick your feet up, watch some Netflix; problem solved.
Not so fast. We have to set it up first. Fortunately, we made that pretty easy too. Most of this is already documented in various guides but I’ll consolidate here for you so it’s easier to find.
The first order of business is: to secure or not to secure? Silly question; of course we’re going to secure but it is worth knowing the option exists. The LDAP client and server are capable of talking straight LDAP over the traditional unsecured 389 port or can be encrypted via certificate to provide TLS security over port 636. Out of the box, 389 access is there but 636 takes a little work.
In order to use LDAP/S, you will first have to install an Active Directory-integrated Certificate Authority, create a new template for the LDAP Proxy and configure group policy to turn on auto-enrollment so the LDAP Proxy server can automatically enroll itself and have the necessary certificate files delivered to the system. I typically do all of this before joining the system so that as soon as I’m joined, I can get right into configurations. While writing this I discovered the handy little guide I’ve been using for months isn’t actually published to the documents library yet. I’m working on fixing that but in the meantime, if you don’t find the Auto-Enrollment Guide there, ask your favorite SE and we’ll happily send you a copy. Follow that, and then come back here.
Welcome back! Now that you have your CA and certificates, let’s move on to configuring both the client and server for TLS and other little tweaks.
If everything went well, you should now have three “auto” certificates sitting in /var/centrify/net/certs on your LDAP Proxy server:
OpenSSL needs the chain file to be in pem format so we’ll generate a fourth file from the existing file:
]$ [dzdo] openssl pkcs7 -in auto_LDAPProxy.chain -text -out auto_LDAPProxy_CA.pem -print_certs
Now you have four certificate files to work with. Next up, let’s configure the client and server to use TLS:
Let’s start with the slapd configuration file. Open up the existing file with your editor of choice, go to the end of the file and add a new section. If you want to be clean about it, you can create a new remark line as well as I’ve done here:
]$ [dzdo] vi /etc/centrifydc/openldap/slapd.conf
Save that away, and we’ll do a similar mapping for the ldap configuration file. Same thing, just add this additional line to the end of the file. This one is much smaller so a comment line may not be necessary:
]$ [dzdo] vi /etc/centrifydc/openldap/ldap.conf
For this next step, we’re creating a whole new file to configure the start-up parameters for the LDAP Proxy server. The purpose here is to configure the listening addresses for the server. That way, even after reboots, your server is started with the correct configurations. Normally, I cover all my bases and configure both the ldap:389 and ldaps:636 for both ‘localhost’ and the fully qualified (DNS) name of the host running the server. In this example, I’ll make up a hostname called hdp1n1.centrifylab.net. Simply replace that name with your own box name.
]$ [dzdo] vi /etc/sysconfig/centrify-ldapproxy
STARTUP_OPTS="-h 'ldap:// hdp1n1.centrifylab.net:389 ldap://localhost:389 ldaps:// hdp1n1.centrifylab.net:636 ldaps://localhost:636'"
We’ll do a quick restart of the service to pick-up these options. I’m using a centOS example so you may have to convert to the service management command that fits your operating system if it’s something else:
]$ [dzdo] service centrify-ldapproxy restart
Check the status:
]$ ps -ef|grep slapd
You should now see the service running with all of the start-up options we configured. If so, we are ready to test.
At this point, I’m also assuming you have an existing Centrify zone with some users and groups already mapped. We’ll use the LDAP Proxy to query all of our enumerated users and groups. Before we do that though, let’s discuss how the LDAP Proxy actually works.
The LDAP Proxy can proxy any query directly to AD but will intercept any queries for either posixaccount or posixgroup objects. In these cases, instead of forwarding the query to Active Directory, it will simply return the information from local cache instead. This is a great, easy way to dump your user and group data, already structured and filtered by zone mapping, without the fuss of having to figure out and crawl Active Directory. You can pass it a BaseDN but we’ll just ignore it and give you zone results no matter where the user actually exists.
We have an ldapsearch tool you can use to verify your results prior to an integration so let’s go to that working directory first:
]$ cd /usr/share/centrifydc/bin/
Next, let’s perform a query for all of our zone users, all attributes:
./ldapsearch -x -H ldaps://localhost:636 -D firstname.lastname@example.org -W "(objectclass=posixaccount)"
Just as in our earlier example, you’ll have to replace the user and domain name with the credentials of an account with permissions to query AD. It will prompt you for the password after executing. In this example, our only filter is by objectclass equaling ‘posixaccount’ so the expected result is all zone users, all attributes since the proxy will intercept this query and return results from cache. If we change ‘posixaccount’ with ‘posixgroup’, the same will happen for all your zone mapped groups. If you want to limit the query even further, you could even search for a particular user/group or only a particular attribute of your users/groups. Here’s an example of such a query where we search for the uidNumber attribute of a user named clusteradm:
./ldapsearch -x -H ldaps://localhost:636 -D email@example.com -W "(&(objectclass=posixaccount)(uid=clusteradm))" uidNumber
Here’s where it gets cool. The proxy server also includes a customizable mapping file, located here:
If you open that file, you will see how we map attribute names to cache items. Anything with an underscore in front of it, means it’s from cache. You can use this file to trick applications who are expecting a value in one format even though it may be something different in AD. This is especially useful if an application badly handles null results. We can stick in another value from cache and work around such issues.
That’s it. We’re done. Queue Eric Idle ‘Always Look On The Bright Side OF Life’ and get back to that beer.
Hopefully you found this helpful. If you have any questions, please feel free to contact either me or your local SE and we would be happy to work with you on this or any other Centrify issue.