Sometimes, instead of replicating a directory information tree, it is desirable to proxy the communication with an LDAP directory. In this scenario a SLAPD server is configured to stand between clients and another LDAP server elsewhere on the network, and respond to client requests with directory information retrieved from the other LDAP server.
OpenLDAP supports a couple of different ways of configuring SLAPD to serve as a proxy.
One way of setting up proxying between two servers is to configure one server to use the ldap
backend (instead of BDB or HDB). The ldap
backend listens for requests and, when it gets them, transparently forwards the request to another LDAP server. For example, say we have two servers, directory.example.com, which stores the database, and proxy.example.com which uses the ldap
backend to proxy requests to the directory.example.com server.
From the client's perspective, when the client connects to proxy.example.com, it appears to get results from proxy.example.com. All network traffic moves between the client and the proxy, and there is nothing in the returned results that indicates that the result were fetched from another server. In addition, the ldap
backend follows referrals automatically, rather then requiring the client application to do referral chasing.
From the perspective of directory.example.com, the connection comes from proxy.example.com.
At the protocol level, the ldap
backend transparently forwards all requests from the client on to the other server. In other words, when the client binds, it is not binding to proxy.example.com but to directory.example.com.
Every client gets its own connection from the proxy to the directory, with one exception. All the clients that connect as the anonymous user are proxied through the same connection to the remote server.
Configuring the ldap
backend to act as a proxy is very simple. Here is a complete slapd.conf
configured for the ldap
backend:
# slapd.conf - Configuration file for LDAP SLAPD ########## # Basics # ########## include /etc/ldap/schema/core.schema include /etc/ldap/schema/cosine.schema include /etc/ldap/schema/inetorgperson.schema include /etc/ldap/schema/blog.schema pidfile /var/run/slapd/slapd.pid argsfile /var/run/slapd/slapd.args loglevel none modulepath /usr/lib/ldap moduleload back_ldap ################ # LDAP Backend # ################ database ldap uri "ldap://directory.example.com" suffix "dc=example,dc=com"
The significant points of this example are highlighted.
Once the back_ldap
module has been loaded, the backend is defined in just three directives. The database directive points to the ldap
backend (instead of the hdb
backend we have been using in previous chapters).
The uri
directive takes as a value a space-separated list of LDAP URLs. In this case there is only one. Having more than one URL comes in handy when one of the servers goes down. When there is a list, the ldap
backend will try to connect to the servers in order. If the first server is down, it will move on to the second URL, and so on until it either runs out of servers or finally makes a connection.
The suffix
directive indicates which suffix or suffixes this backend serves. This should contain the base DN or DNs that the remote directory provides. It is possible to use the proxy to make available only a branch or two of the remote server using this method. For example, the remote server might provide access to dc=example,dc=com
. But we could set the suffix on this proxy to ou=users,dc=example,dc=com
, and users of this server would then only be able to search that part of the directory information tree through this proxy.
There are a handful of other configuration options available for the ldap
backend, all of which are document in the slapd-ldap
man page: man
slapd-ldap
. But we will only look at one subset: the identity management features.
There are more sophisticated things that can be done with the ldap
backend. You can, for instance, separate the authentication and authorization tasks, authenticating as the DN supplied by the client but then performing all work as a different user.
This feature, called ID assertion, allows you to set up a proxy (perhaps accessible on a less secure network) that can allow users to bind as themselves, but then use an account with lower permissions (such as a system account whose permissions are restricted by ACLs) to get only a limited subset of information from the directory.
Configuring ID assertion requires only a few additional directives. On the proxy, you will need to add two directives to the ldap
database configuration: idassert-bind
and idassert-authzFrom
.
The idassert-bind
directive specifies how the proxy server ought to authenticate to the remote directory server. Here's an example configuration:
idassert-bind bindmethod=simple binddn="uid=authenticate,ou=system,dc=example,dc=com" credentials="secret" mode=none
This directive defines the account (and authentication style) that the proxy will use to connect to the remote directory in order to authenticate the client.
The supported values of bindmethod
are simple
(to do a simple bind), sasl
(to do SASL binds), and none
. If none
is used then ID assertion is not done (which achieves the same effect as not using this directive at all).
The binddn
and credentials
parameters specify the DN and password for connecting to the remote directory.
The mode parameter specifies whose identity will be asserted to the remote server. In the given example we set the mode to none
, which means that the proxy will assert the DN specified in binddn
as its identity. In other words, the proxy will perform all operations on the remote server as the DN in binddn
.
For a more complicated proxy, you can set mode
to anonymous
(which asserts the anonymous identity to the remote directory) or self
(which asserts the identity sent by the client). These implement the Proxied Authorization (proxyAuth) Control defined in RFC 4370 (http://www.rfc-editor.org/rfc/rfc4370.txt).
For anonymous
or self
, you may also need to set the authz-policy
directive in ldap.conf
, and add authzFrom
or authzTo
entries to the proxy's or client's DN (respectively). For more information see the man pages for slapd.conf
and slapd-ldap
.
The idassert-authzFrom
directive is used to authorize which clients can make use of the proxy. For example, we could set a rule that allows users to use the proxy if their DNs are in the ou=users
subtree:
idassert-authzFrom dn.subtree="ou=users,dc=example,dc=com"
Like other directives that make use of the dn
specifier, this one supports the regular list of modifiers, like dn.subtree
, dn.one
, and dn.regex
. See the discussion of limits in Chapter 5 for an explanation of these modifiers.
As we have configured the proxy so far, every request to the proxy is relayed to the remote directory server. No results are retained on the proxy. So when the same request is performed several times, the proxy connects to the remote directory server each time and forwards the request. It is possible, however, to use the pcache
(Proxy Cache) overlay to add caching to the proxy, storing a subset of the remote directory on the proxy. This can significantly speed up performance in some cases.
Proxy Cache works by storing a subset of frequently-accessed information in a database on the proxy SLAPD instance. When the proxy receives a request for information stored in the cache, it will return the cached data instead of fetching the records from the remote server.
Records are stored in an LRU (Least Recently Used) cache, which means that once the cache fills up, the records that were accessed least recently are removed to make way for new entries. Additionally, an entry is only served out of the cache for a certain period of time (called Time To Live, or TTL) before the proxy once again connects to the remote directory to fetch a fresh copy of the entry. This keeps the proxy from serving stale or out of date information that has changed in the main directory since the last time the proxy accessed the records.
The pcache
overlay is configured in the proxy's slapd.conf
file. The first few steps of implementing the pcache
overlay are familiar. Near the top of our configuration file we need to add the moduleload
pcache
line to load the correct module.
In the database section we need to add the pcache
overlay with the usual overlay
directive. Then, there are several directives necessary to configure the pcache
overlay. Here is the entire database configuration section for an ldap
database with the proxy cache overlay:
database ldap uri "ldap://10.21.77.100" suffix "dc=example,dc=com" rootdn "cn=Manager,dc=example,dc=com" idassert-bind bindmethod=simple binddn="uid=authenticate,ou=system,dc=example,dc=com" credentials="secret" mode=none idassert-authzFrom "dn.subtree:dc=example,dc=com" overlay pcache proxycache bdb 1000 1 50 1200 directory /var/lib/ldap/cache index objectclass eq index uid,mail eq,sub index queryid eq proxycachequeries 100 proxyattrset 0 uid mail cn sn givenName proxytemplate (uid=) 0 600
The beginning of the file does not differ much from the identity assertion configuration we used in the previous section. One difference however, is the addition of the rootdn
directive which is required by the database-backed pcache
overlay. It is never used for authentication purposes so using the base DN of the directory is fine.
Once the overlay has been added to the overlay stack using overlay
pcache
, the first proxy cache directive appears:
proxycache bdb 1000 1 50 1200
This directive handles the core configuration of the proxy cache engine. It has five different parameters:
pcache
needs a place to store the cached data, and it can use one of the underlying database mechanisms such as bdb
, hdb
, or ldif
. If you want an efficient storage system, bdb
or hdb
are the best choices. Later in the configuration, we will have to set some directives for the database.1
.50
in this case) will not be cached.The first field in the proxycache
directive is the database type, specifying what database backend will be used to store cached data. Now we need to add a few directives to configure that database backend:
directory /var/lib/ldap/cache index objectclass eq index uid,mail eq,sub index queryid eq
The directory
directive (a familiar one we used when configuring the HDB backend in Chapter 3) points to the directory where the BDB files will be stored.
If you set directory
to a location that doesn't exist yet, make sure to create that directory on the file system: mkdir
/var/lib/ldap/cache
. You should also put a copy of the DB_CONFIG
file in the cache/
directory, or else the default Berkeley DB settings will be used, and those usually result in poor performance.
After the database directive, there are several index directives which specify which indexes ought to be created and what types of searches each should support. As usual, these index files can be used to expedite performance.
There are two indexes that should definitely be included: an equality index on objectclass
, and an equality index on queryid
. The queryid
index is specific to the pcache
backend which uses queryid
to identify queries cached in the database. Other indexes should be specified where they will increase lookup speeds for the queries defined in the proxy cache templates (which we will examine in a moment).
You can also use other directives (like cachesize
) that are defined for the BDB backend. See the discussion in Chapter 5 and the man page for slapd-bdb
for more detail.
Now we have a few more pcache-specific directives to examine:
proxycachequeries 100 proxyattrset 0 uid mail cn sn givenName proxytemplate (uid=) 0 600
The proxycachequeries
directive specifies how many queries (not entries) should be cached.
The proxyattrset
directive indicates what attributes ought to be cached. The proxy cache stores a subset of the remote directory. That subset is not merely a subset of the total entries, but also a subset of the attributes for each entry. In the example here, this proxyattrset
specifies that only the uid
, mail
, cn
, sn
, and givenName
attributes (and their values) should be cached. A request for any other attribute will be proxied to the remote server.
The proxyattrset
directive has two parts:
0
for the first proxyattrset
, 1
for the second, and so on There can be more than one proxyattrset
, but the total number of proxyattrset
directives must be explicitly specified in the proxycache
directive. In our configuration, we only have one proxyattrset
directive, so the third parameter (the number of attribute sets) in the proxycache
directive is set to 1
.
The last directive is the proxytemplate
directive. A filter template specifies what sort of searches will be stored in the cache, and indicates which attributes will be stored for records that match the search filter. The directive has three parameters:
proxyattrset
directive to useA filter template is a variation on a regular LDAP filter. A regular filter might look like this: (uid=m*)
, or (&(ou=users)(objectclass=person))
. A filter template is a filter without the asserted value; that is, it is a template with nothing on the right-side of the equals sign. (uid=)
and (&(ou=)(objectclass=))
are filter templates for the two search filters.
If an incoming search's filter matches the filter template (and it doesn't return more than the maximum number of results) then it will be handled by the cache. For example, the filters (uid=*)
, (uid=mat*)
and (uid=dave)
all match the filter template (uid=)
. They can be handled by the cache, but (&(uid=*)(ou=system))
cannot as it doesn't match a defined filter template.
The second parameter is the numeric identifier for the proxyattrset
directive that should be used. In our example we set this to 0
, which uses proxyattrset
0
. Thus, this filter template caches the values of the uid
, mail
, cn
, sn
, and givenName
attributes.
The proxyattrset
directive is used to determine whether to serve incoming searches from the cache or by connecting to the remote directory. If the request matches a search filter template, and the attributes list supplied by the client has only attributes in proxyattrset
, then results may be served out of the proxy cache. For example, if a request comes in with the search filter (uid=m*)
(which matches the (uid=)
template) and requests the uid
, mail
, and sn
attributes, these results can be served out of the cache. On the other hand, if the attributes list is uid
, mail
, and telephoneNumber
, then the cache will be skipped and the proxy will fetch the information from the remote server. Why is this? Simply because one of the attributes, telephoneNumber
, is not stored in the cache at all, and so the pcache
overlay cannot fulfill the entire request.
The third parameter for the proxytemplate
directive is the TTL. This specifies how many seconds an entry can be in the cache before it is considered stale and removed or refreshed.
There is a special fourth parameter that can be used too: the so-called Negative TTL. By default, the proxy cache caches only successful requests. That is, if a search request is made, and the remote directory returns zero records, no information is cached.
Sometimes, however, it might be useful to cache a "miss," so that if the same query comes in again it can be immediately served from the cache, instead of requiring another trip to the remote directory—a trip likely to result in the same empty result set. The negative TTL parameter allows you to turn on caching of misses, and also set the number of seconds that a negative result (a record of a miss) should be retained in the cache.
One of the potentially confusing things about the proxy cache overlay is the relationship between attribute sets and filter templates (and the proxycache
directive's count of attribute sets).
Every attribute set should be referenced by at least one filter template. But multiple filter templates can use the same attribute set. For example, the following is legitimate:
proxycachequeries 100 proxyattrset 0 uid mail cn sn givenName proxytemplate (&(mail=)(objectclass=)) 0 600 proxytemplate (uid=) 0 600
In this case, both filter templates refer to the same attribute set (the one with the ID number 0
).
The same template can be used with different attribute sets. Here's what happens under such circumstances. Consider the following:
overlay pcache proxycache bdb 1000 2 50 1200 # ... skipped a few lines... proxyattrset 0 uid mail cn sn givenName proxyattrset 1 uid description proxytemplate (uid=) 0 600 proxytemplate (uid=) 1 600
The above is legal and works but has interesting results.
If a search is done for (uid=m*)
requesting uid
and mail
, a cache entry will be generated for the first attribute set.
But if a search is done for (uid=m*)
requesting uid
and description
, then an entry is generated for the second attribute set.
If a search is done for (uid=m*)
requesting mail
and description
, it will miss both caches and results will be retrieved from the remote server.
The proxy cache overlay can turn the ldap
backend into more than just a simple proxy. By tuning the attribute sets and templates to match frequently used queries, you can use pcache
to improve the responsiveness of the proxy and reduce the amount of traffic to the remote directory.
Consider the following situation. A remote directory contains the basic information that you need. You want to create an LDAP proxy to that directory but there are a few values that you want to modify on the proxy (but not on the remote directory).
This can be done with the translucent
overlay, which proxies requests to a remote directory, but also allows attributes to be locally modified and stored while not modifying the remote directory information tree. This sort of hybrid proxy is called a translucent proxy.
We will briefly take a look at configuring a translucent proxy.
As usual, near the top of the slapd.conf
file of the proxy, we will need to load the translucency module. We will also need the LDAP and BDB module, since both backends will be used:
moduleload back_ldap moduleload back_bdb moduleload translucent
Now we can skip ahead in the configuration file to the database section.
For a translucent proxy we will need to configure it to store some information locally, but also act like a proxy and retrieve information from a remote directory server. Here is a sample configuration for the transparent
overlay:
database bdb directory /var/lib/ldap/transparent suffix "dc=example,dc=com" rootdn "uid=authenticate,ou=system,dc=example,dc=com" rootpw secret index objectclass eq index uid eq,sub lastmod off overlay translucent uri "ldap://10.21.77.100" idassert-bind bindmethod=simple binddn="uid=authenticate,ou=system,dc=example,dc=com" credentials="secret" mode=none idassert-authzFrom "dn.subtree:dc=example,dc=com"
The transparent
overlay uses a database (in this case the bdb
backend) to store information locally, and then implicitly uses the ldap
backend to connect to the remote directory. As with the pcache
overlay, it is best to use BDB or HDB for the backend data storage mechanism.
For the bdb
backend configuration, we need the usual directives: directory
, suffix
, rootdn
, rootpw
, and one or more index
directives (we should at least have an equality index on objectclass
).
We also turn off modification timestamps (lastmod
off
) so that SLAPD doesn't automatically generate the corresponding modifiersName
and modifyTimestamp
operational attributes. You can remove this line if you want that information to be stored in the proxy's database but, when a client requests a record from the proxy, it will see different modification information than it would see if connecting to the remote directory.
The rootdn
and rootpw
password play a special role in a translucent proxy. This DN is the only user that can add new records to the proxy's database. And any LDAP modification, add, or modRDN operations that come from this user will change only the local copy of the data.
The root DN can only access values on the remote server that it is allowed to access, but it can add or modify any record on the local translucent database. This means, effectively, that it may be able to write entries into branches of the directory tree that it cannot access (because of ACLs on the remote directory).
Now we have the backend database configured. Next, we want to configure the translucent
overlay.
After the overlay
directive, inserting translucent
into the overlay stack, we need to supply the translucent
overlay with information about the remote directory.
Since the translucent
overlay uses the ldap
backend, any ldap
backend parameters can be used here:
overlay translucent uri "ldap://10.21.77.100" idassert-bind bindmethod=simple binddn="uid=authenticate,ou=system,dc=example,dc=com" credentials="secret" mode=none idassert-authzFrom "dn.subtree:dc=example,dc=com"
The uri
directive is used to point the translucent proxy to the remote server. And again we use the identity assertion discussed earlier in this chapter to handle authorization to information from the remote server.
Now let's examine a few examples of the translucent proxy in action. First, we can grab a record proxied from the remote server:
$ ldapsearch -x -W -D 'uid=matt,ou=users,dc=example,dc=com' \ -H ldap://proxy.example.com -b 'dc=example,dc=com' -LLL '(uid=manny)' Enter LDAP Password: dn: uid=manny,ou=Users,dc=example,dc=com sn: Kant uid: immanuel uid: manny ou: Users objectClass: person objectClass: organizationalPerson objectClass: inetOrgPerson givenName: Manny cn: Manny Kant
In this example we use ldapsearch
to connect to the proxy (ldap://proxy.example.com
) and retrieve the record with uid=manny
.
This operation causes the proxy to retrieve the record from the remote server. It then compares that record to the information in its own database of modifications and, if any local modifications to that record apply, they will be inserted into the resulting record.
Let's say that we want to add a description
field to Manny's record, but we only want that field to exist on the proxy not on the remote directory. We can accomplish this by using ldapmodify
, and authenticating as the root DN for the proxy (uid=authenticate,ou=system,dc=example,dc=com
):
$ ldapmodify -x -W \ -D 'uid=authenticate,ou=system,dc=example,dc=com'\ -H ldap://proxy.example.com Enter LDAP Password: dn: uid=manny,ou=users,dc=example,dc=com changetype: modify add: description description: This was added only to the proxy. modifying entry "uid=manny,ou=users,dc=example,dc=com"
This modification simply adds the description attribute along with the message: This was added only to the proxy.
Now the modification should have been written only to the translucent database. As a result we should be able to repeat our search before against the proxy and see the new description field:
$ ldapsearch -x -W -D 'uid=matt,ou=users,dc=example,dc=com' \ -H ldap://proxy.example.com -b 'dc=example,dc=com' -LLL \ '(uid=manny)' Enter LDAP Password: dn: uid=manny,ou=Users,dc=example,dc=com sn: Kant uid: immanuel uid: manny ou: Users objectClass: person objectClass: organizationalPerson objectClass: inetOrgPerson givenName: Manny cn: Manny Kant description: This was added only to the proxy.
When the proxy receives this search operation, it requests the entire record for uid=manny
from the remote directory. That record looks something like this (plus the operational attributes, which are not shown):
dn: uid=manny,ou=Users,dc=example,dc=com sn: Kant uid: immanuel uid: manny ou: Users objectClass: person objectClass: organizationalPerson objectClass: inetOrgPerson givenName: Manny cn: Manny Kant
The translucent proxy then compares that record with its own, which looks like this:
dn: uid=manny,ou=users,dc=example,dc=com description: This was added only to the proxy.
The two records are then merged, with changes to the translucent database taking precedence over those from the remote directory. The result is the appending of the description
attribute to the end of the returned record.
But how do we know that this modification wasn't written to the remote directory? We can run a search on that directory and see the unchanged record:
$ ldapsearch -x -W -D 'uid=matt,ou=users,dc=example,dc=com' \ -H ldap://directory.example.com -b 'dc=example,dc=com' -LLL \ '(uid=manny)' Enter LDAP Password: dn: uid=manny,ou=Users,dc=example,dc=com sn: Kant uid: immanuel uid: manny ou: Users objectClass: person objectClass: organizationalPerson objectClass: inetOrgPerson givenName: Manny cn: Manny Kant
A transparent proxy can be used to provide local modification of entries that are otherwise controlled externally. Like the other forms of proxying, there is no OpenLDAP-specific remote directory, the transparent proxy can use any standards-compliant LDAP v3 directory as a remote directory.