# Configuring LDAP

This page describes how to configure LDAP (Lightweight Directory Access Protocol) as an authentication mode in an Aerospike Database Enterprise Edition (EE) deployment.

## Overview

Aerospike Database’s role-based access control (RBAC) supports LDAP as an _external authentication_ method where users log in using credentials from a third-party service. Their user information is stored and verified outside of the organization’s direct control.

LDAP works separately or concurrently with other authentication modes such as PKI.

LDAP is supported on Aerospike Database Enterprise Edition or Aerospike Database Enterprise Edition for United States Federal (FE).

### Requirements

The following settings are required in `features.conf`, the [`feature-key-file`](https://aerospike.com/docs/database/reference/config#service__feature-key-file), and in [`aerospike.conf`](https://aerospike.com/docs/database/8.1.0/manage/database/as-config#sample-configuration-file).

-   In [`features.conf`](https://aerospike.com/docs/database/reference/config#service__feature-key-file), `asdb-ldap` must me set to `true`.
-   [`aerospike.conf`](https://aerospike.com/docs/database/8.1.0/manage/database/as-config#sample-configuration-file) must have a `security` stanza with an `ldap` sub-stanza. You will do this in Step 5.

## Enable LDAP for access control

1.  Create a CN (common name) group file on the LDAP server. The following example creates a group named read-write-udf. This is the user name.
    
    ```plaintext
    cat read-write-udf.ldif
    
    dn: cn=read-write-udf,dc=field,dc=aerospike,dc=com
    
    objectClass: top
    
    objectClass: posixGroup
    
    gidNumber: 680
    ```
    
2.  Create the group on the Aerospike server with the user name as the CN group file.
    
    ```plaintext
    `ldapadd -x -w admin -D "cn=admin,dc=field,dc=aerospike,dc=com" -f read-write-udf.ldif`
    ```
    
3.  Create a file on the Aerospike server with the user name to map to the CN group.
    
    ```plaintext
    cat modify.ldif
    
    dn: cn=read-write-udf,dc=field,dc=aerospike,dc=com
    
    changetype: modify
    
    add: memberuid
    
    memberuid: aerospike
    ```
    
4.  Modify the LDAP group and associate the user name.
    
    ```plaintext
    ldapmodify -x -w admin -D "cn=admin,dc=field,dc=aerospike,dc=com" -f modify.ldif
    ```
    
5.  Add a `security` stanza that includes an `ldap` sub-stanza to `aerospike.conf`. Include the following settings for LDAP-privileged users:
    
    -   `query-user-dn`\- setting for an LDAP privileged user with permission to query LDAP and
    -   `query-user-password-file` - clear text password file to that LDAP privileged user
    
    The following sample shows a configuration for a TLS-enabled LDAP server over port 389. In this configuration, the Aerospike server contacts the LDAP server over TLS and authenticates using the user specified in `query-user-dn`.
    
    ```plaintext
    security {
    
        ldap {
    
            query-base-dn dc=field,dc=aerospike,dc=com
    
            query-user-dn cn=admin,dc=field,dc=aerospike,dc=com
    
            query-user-password-file /etc/aerospike/passwordldap.txt
    
            server ldap://127.0.0.1:389
    
            disable-tls false
    
            tls-ca-file /etc/openldap/certs/myldap.field.aerospike.com.cert
    
            user-dn-pattern uid=${un},ou=People,dc=field,dc=aerospike,dc=com
    
            role-query-search-ou false
    
            role-query-pattern (&(objectClass=posixGroup)(memberUid=${un}))
    
            polling-period 10
    
        }
    
        log {
    
            report-violation true
    
        }
    
    }
    ```
    

## Optional settings in aerospike.conf

For detailed examples of the following configuration parameters in use, see [Example LDAP configurations](#example-ldap-configurations).

| 
Desired configurations

 | 

Example stanzas and parameters

 |
| --- | --- |
| 

-   The configuration file must have a `security` stanza, which must include an `ldap` sub-stanza.
-   These two stanzas enable security and LDAP.

 | 

```plaintext
security {

    ... security settings

    ldap {

       ... LDAP settings

    }
```





 |
| 

Because passwords are sent in cleartext to the LDAP service, Aerospike strongly recommends that you implement Transport Layer Security (TLS).

-   For TLS, the `network` stanza of the configuration file must include the [`tls`](https://aerospike.com/docs/database/reference/config#network__tls) parameter and definitions of hostnames, cluster names, or other settings depending on your configuration.
-   For full example configurations, see [Transport Layer Security (TLS)](https://aerospike.com/docs/database/8.1.0/learn/security/tls) and [TLS Configuration](https://aerospike.com/docs/database/8.1.0/manage/network/tls).

 | 

```plaintext
network {

  tls tlsname1 {

    ... TLS settings

  }

  tls tlsname2 {

    ... TLS settings

  }

  ...

}
```





 |
| 

If you are using cross-datacenter replication (XDR):

-   The configuration file must enable XDR with an `xdr` stanza.
-   In the `xdr` stanza, for each datacenter definition that should authenticate with LDAP, the parameter [`auth-mode`](https://aerospike.com/docs/database/reference/config#xdr__auth-mode) should be set `external`. _Aerospike recommends that you do not set `auth-mode` to `external-insecure`_.
-   Full example XDR configurations are in [Cross-Datacenter Replication (XDR)](https://aerospike.com/docs/database/8.1.0/manage/xdr/static-xdr).

 | 

```plaintext
xdr {

        dc someDataCenter {

               auth-mode external

               ... other datacenter settings

        }

        ...

  }
```





 |

### Optional LDAP settings

-   In the `security` stanza, the optional [`ldap-login-threads`](https://aerospike.com/docs/database/reference/config#security__ldap-login-threads) specifies the number of threads to use for LDAP logins.

All other LDAP options belong to the `ldap` sub-stanza of the security stanza.

-   [`disable-tls`](https://aerospike.com/docs/database/reference/config#security__disable-tls) `<true|false>` whether to disable the use of TLS for LDAP server connections.
-   [`polling-period`](https://aerospike.com/docs/database/reference/config#security__polling-period) `<integer>` how frequently (in seconds) to query the LDAP server for user group membership information. Allowable range is 0 to 86400 (24 hours). A value of 0 means do not poll. Default: 300 (5 minutes). Dynamic.
-   [`query-base-dn`](https://aerospike.com/docs/database/reference/config#security__query-base-dn) `<string>` distinguished name of the LDAP directory entry at which to begin the search when querying for a user’s group membership information. Required option. Certain characters in the value of this parameter must be escaped. See [Parameters whose values must be escaped](#parameters-whose-values-must-be-escaped).
-   [`query-user-dn`](https://aerospike.com/docs/database/reference/config#security__query-user-dn) `<string>` distinguished name of the user designated for user group membership queries. Certain characters in the value of this parameter must be escaped. See [Parameters whose values must be escaped](#parameters-whose-values-must-be-escaped).
-   [`query-user-password-file`](https://aerospike.com/docs/database/reference/config#security__query-user-password-file) `STRING` path to file containing clear text password for the user designated for user group membership queries.
-   [`role-query-base-dn`](https://aerospike.com/docs/database/reference/config#security__role-query-base-dn) `<string>` if specified uses this value as the base dn when performing the role queries. Default: `query-base-dn` value is used. Certain characters in the value of this parameter must be escaped. See [Parameters whose values must be escaped](#parameters-whose-values-must-be-escaped).
-   [`role-query-pattern`](https://aerospike.com/docs/database/reference/config#security__role-query-pattern) `<string>` – format for the search filter to use when querying for a user’s group membership information. The substitutions for username, `${un}`, and distinguished name, `${dn}` will be replaced by the actual username and the actual user’s full distinguished name when constructing the search filter. If needed, multiple role-query-pattern strings can be specified separately and each will be tried in order when querying for a user’s information. Required option.
-   [`role-query-search-ou`](https://aerospike.com/docs/database/reference/config#security__role-query-search-ou) `<true|false>` whether to look for a user’s group membership information in the organizational unit entries of the user’s LDAP distinguished name. Default: false
-   [`user-dn-pattern`](https://aerospike.com/docs/database/reference/config#security__user-dn-pattern) `<string>` format for the distinguished name of the LDAP directory entry to use when binding to the LDAP server for user authentication.
    -   Either `user-dn-pattern` or `user-query-pattern` is required.
    -   The literal `${un}` must be placed in this string to specify where the user ID is inserted when Aerospike Database constructs the distinguished name.
    -   Certain characters in the value of this parameter must be escaped. See [Parameters whose values must be escaped](#parameters-whose-values-must-be-escaped).
    -   For examples, see [LDAP Direct Bind vs Query User DN authentication](#ldap-direct-bind-vs-query-user-dn-authentication).
-   [`user-query-pattern`](https://aerospike.com/docs/database/reference/config#security__user-query-pattern) `<string>` format for the search filter to use when querying for a user’s distinguished name.
    -   Either `user-query-pattern` or `user-dn-pattern` is required.
    -   The literal `${un}` must be placed in this string to specify where the user ID is inserted when Aerospike Database constructs the search filter.
    -   For examples, see [LDAP Direct Bind vs Query User DN authentication](#ldap-direct-bind-vs-query-user-dn-authentication).
    -   As of Database 5.1.0, Aerospike escapes certain illegal characters in the user DN returned by the LDAP server before making role queries for the user. Previous versions would fail querying the LDAP server if such characters are present. The characters that are escaped are as follows:
        -   \*
        -   (
        -   )
        -   \\
        -   /
        -   space
-   [`server`](https://aerospike.com/docs/database/reference/config#security__server) `domainNameOfLDAPserver` name of the LDAP server to use. Multiple servers can be specified using a comma-delimited string without whitespace. Required option.
-   [`session-ttl`](https://aerospike.com/docs/database/reference/config#security__session-ttl) `integer` lifetime (in seconds) of an access token. A TCP connection attempt with an expired token will fail, and the client must log in again to get a fresh token.
-   [`tls-ca-file`](https://aerospike.com/docs/database/reference/config/#security__tls-ca-file) `string` path to the CA certificate file used for validating TLS connections to the LDAP server. Must end with the file name, like `/path/to/CA/cert/file`. Required FOR TLS.
-   [`token-hash-method`](https://aerospike.com/docs/database/reference/config#security__token-hash-method) `string` hash algorithm to use when generating the HMAC for access tokens.

#### Parameters whose values must be escaped

The values of certain configuration parameters must escape some certain illegal characters. The parameters are as follows:

-   [`query-base-dn`](https://aerospike.com/docs/database/reference/config#security__query-base-dn)
-   [`query-user-dn`](https://aerospike.com/docs/database/reference/config#security__query-user-dn)
-   [`role-query-base-dn`](https://aerospike.com/docs/database/reference/config#security__role-query-base-dn)
-   [`user-dn-pattern`](https://aerospike.com/docs/database/reference/config#security__user-dn-pattern)

The characters that must be escaped are as follows. The escape must use the hexadecimal representation of the character.

| text character | Hexadecimal representation |
| --- | --- |
| `*` asterisk | `\2A` |
| `(` left parenthesis | `\28` |
| `)` right parenthesis | `\29` |
| `\` backslash | `\5C` |
| `/` slash | `\2F` |
| space | `\20` |

### Settings in client API

For the client application to use LDAP, the client call must set the authentication mode to `EXTERNAL`. Client authentication mode can be used with or without XDR configured on the server. For example, for details for the C client, see [Enum AuthMode](https://aerospike.com/apidocs/java/com/aerospike/client/policy/AuthMode.html).

## LDAP Direct Bind vs query user DN authentication

The Aerospike server takes a username and maps it to an LDAP Distinguished Name (DN). The DN is then used for the authentication (bind) request and, in some cases, querying for groups.

You must set the configuration parameter `user-query-pattern` if the username is not in the DN which is often the case for Active Directory, or if user DNs are in different organizational units (OUs). This query must return exactly one user record from which the DN is extracted. For example in Active Directory the configuration is something like the following, the username gets substituted in for the `${un}`.

```text
user-query-pattern (&(objectCategory=Person)(sAMAccountName=${un}))
```

In such a case, if the username is `jane_doe`:

-   The actual query would be `(&(objectCategory=Person)(sAMAccountName=jane_doe))` .
-   The query would return the entry with a DN of `cn=Jane Doe,ou=People,dc=janetsoft,dc=com`

In the special case where the system’s user’s DNs always follow the same pattern with the username embedded, like for a fictitious company named “Johnny Corp”, `uid=johnny_doe,ou=People,dc=johnnycorp,dc=com`, the Aerospike server saves one extra query to configure the `user-dn-pattern` directly and not `user-query-pattern`. For example, in Johnny Corp’s case, the configuration parameter would be as follows. No extra user lookup query will be made and the substituted DN will be used.

```text
user-dn-pattern uid=${un},ou=People,dc=johnnycorp,dc=com
```

### LDAP group mapping

For easier management through a set of LDAP queries, Aerospike uses the external LDAP server to provide the mapping from an individual username to a list of groups. The Aerospike server configuration is described in the section LDAP Users and Groups below.

The results of this request are stored in Aerospike’s shared System Metadata store (SMD). This allows the query responses to be shared among all Aerospike servers, reducing the query load. This request is done on a repeated basis (configurable time). If the response shows that the user has been deleted or the user has been modified, all servers will be quickly notified of the change, and all authorization will use the new authorization – including existing in-flight connections.

Aerospike’s SMD store also includes the time that the data was last updated. Aerospike will be configured to not use data past a certain age, providing some resiliency in case of LDAP server failure, but also providing protection in case of an LDAP DOS attack.

Through this mechanism, changes in user authorization and authentication are quickly learned and applied throughout the cluster, on a time-bounded basis.

::: note
When a new node is added to an existing cluster, it is a [best practice](https://aerospike.com/docs/database/8.1.0/learn/best-practices/#initialize-new-cluster-nodes-with-smd) to initialize it by copying [SMD](https://aerospike.com/docs/database/8.1.0/manage/database/directory-structure/#run-time-directories) files from an existing cluster node.
:::

The mapping of groups to individual access rights will be done through existing Aerospike configuration mechanisms, and use the existing Aerospike logging and levels. An administrator will need to create a set of groups, and determine the privilege levels of those groups, and set those groups in Aerospike using the already existing and provided tools.

### LDAP users and groups

Organizing users and giving permissions in LDAP is flexible. The supported groupings to use for Aerospike roles fit into two categories:

-   Groupings of users that can be Posix groups, OUs like “groupOfUniqueNames”, or any other entry that can be queried using either username or DN of the user. The role-query-pattern(s) are used to find these groups :
    
-   role-query-pattern contains an LDAP query to search for an entry. Multiple may be specified for cases where groups are kept in different locations or need different queries. The queries will be run in order and all entries found will be collected.
    

An example configuration is as follows:

```text
role-query-pattern (&(objectclassName=posixGroup)(memberUid=${un}))

role-query-pattern (&(ou=db_groups)(uniqueMember=${dn}))

role-query-pattern (&(ou=admins)(uniqueMember=uid=${un},dc=blastcorp,dc=com))
```

Note the substitutions for username, `${un}`, and distinguished name, `${dn}`. These will be replaced by the actual username and the actual user’s full distinguished name when the queries are run.

-   User’s position in LDAP tree In some setups the user’s position within a directory tree is what determines their privilege level. For example a user such as `uid=jim,ou=Users,ou=Admins,dc=blastcorp,dc=com` might have groups of privileges for “Users” as well as for “Admins”. If this is the case, setting role-query-search-ou to true will treat the OUs in the user’s DN as potential roles.

In all cases the CN of the entry must match an Aerospike role name to be detected as such; any others will be ignored.

## Example LDAP configurations

Below are examples of LDAP configurations.

::: note
These examples assume Aerospike Database 5.7.0 or later, where the [`enable-security`](https://aerospike.com/docs/database/reference/config#security__enable-security) and [`enable-ldap`](https://aerospike.com/docs/database/reference/config#security__enable-ldap) configuration items are obsolete, and the presence of either of these items in the configuration file will prevent the server from starting.
:::

These examples cannot be used directly and must be modified to match you own systems.

### Example basic aerospike.conf parameters for LDAP

The values shown here are only examples.

```text
security {

    ...

    ldap {

    # Base DN

        query-base-dn o=LDAPvalueOfO,dc=valueOfDC,dc=com

    # Domain name or IP address and port of LDAP servers

        server ldap://someDomainMame:somePort

    # TLS

        disable-tls false

    # Location of the cert file for TLS communication with LDAP server

        tls-ca-file /pathToSomeCertFile

    # DN of the Aerospike "trusted user" to query for roles

        query-user-dn uid=as_user,ou=Users,o=5a7b4b08f4f3414e69eb5f8c,dc=jumpcloud,dc=com

    # Path to cleartext password of the same user

        query-user-password-file /some/path/to/the_query_user_password.txt

    # Set this true to treat the OUs of the users' DN as possible roles

        role-query-search-ou true

    # This query is to search for other entries to use for roles.

    # In this case the ${dn} is replaced with the user's full DN

        role-query-pattern (&(objectclassName=groupOfNames)(member=${dn}))

    # How often to poll for new roles in seconds.

        polling-period 10

    # Pattern to look up user. ${un} is replaced with the username

        user-query-pattern (uid=${un})

    }

    ...

}
```

### Example parameters for XDR auth-mode

The `xdr` stanza needed for LDAP with XDR enabled and `auth-mode external` is shown in [Cross-Datacenter Replication (XDR)](https://aerospike.com/docs/database/8.1.0/manage/xdr/static-xdr/).

### Example JumpCloud’s LDAP directory-as-a-service

```text
security {

    ...

    ldap {

    # base dn will be different for every jumpcloud instance

        query-base-dn o=5a7b4b08f4f3414e69eb5f8c,dc=jumpcloud,dc=com

    # ldap server(s) to use

        server ldap://ldap.jumpcloud.com:389

    # this is the default, but we want to use tls

        disable-tls false

    # location of the cert file needed for TLS communication with the jumpcloud server

        tls-ca-file /etc/ssl/certs/jumpcloud.chain.pem

    # this is the dn of the aerospike "trusted user" which queries for roles

        query-user-dn uid=as_user,ou=Users,o=5a7b4b08f4f3414e69eb5f8c,dc=jumpcloud,dc=com

    # path to cleartext password of the same user

        query-user-password-file /some/path/to/the_query_user_password.txt

    # set this to true to treat the OUs of the users dn as possible roles

        role-query-search-ou true

    # this query will be used to search for other entries to use for roles.

    # in this case the ${dn} will be substituted with the user's full dn

        role-query-pattern (&(objectclassName=groupOfNames)(member=${dn}))

    # how often to poll for new roles. We are doing it every 10 seconds for development testing

        polling-period 10

    # pattern to look up user. ${un} will be replaced with the username

        user-query-pattern (uid=${un})

    }

    ...

}
```

### Example Active Directory configuration

Query user DN, no TLS, trusted role poling user, and multiple group types:

```text
security {

    ldap {

        query-base-dn dc=aerospike,dc=com

        server ldap://blast.aerospike.com:389

        # This server does not support TLS

        disable-tls true

        query-user-dn CN=Trusted\20User,CN=Users,DC=aerospike,DC=com

        query-user-password-file  /path/to/password_file.txt

        role-query-search-ou true

        role-query-pattern (&(objectclassName=posixGroup)(memberUid=${un}))

        role-query-pattern (&(objectclassName=group)(member=${dn}))

        role-query-pattern (&(ou=*)(uniqueMember=uid=${un},dc=aerospike,dc=com))

        polling-period 20

        user-query-pattern (sAMAccountName=${un})

    }

    log {

        report-violation true

    }

}
```

### Example OpenLDAP configurations

Direct bind pattern, TLS, anonymous role binding, and POSIX groups:

```text
security {

    ldap {

        query-base-dn dc=aerospike,dc=com

        server ldap://localhost:389

        tls-ca-file /etc/ssl/certs/ca_server.pem

        user-dn-pattern uid=${un},ou=People,dc=aerospike,dc=com

        role-query-search-ou true

        role-query-pattern (&(objectclassName=posixGroup)(memberUid=${un}))

        polling-period 10

    }

    log {

        report-violation true

    }

}
```

Query user DN, TLS, trusted role polling user, and multiple group types:

```text
security {

    ldap {

        query-base-dn dc=aerospike,dc=com

        server ldap://ldaptest.aerospike.com:389,ldap://localhost:389

        tls-ca-file /etc/ssl/certs/ca_server.pem

        query-user-dn uid=aero,dc=aerospike,dc=com

        query-user-password-file /path/to/password_file.txt

        role-query-pattern (objectclassName=group)

        role-query-pattern (&(ou=*)(uniqueMember=uid=${un},dc=aerospike,dc=com))

        role-query-pattern (&(objectclassName=posixGroup)(memberUid=${un}))

        polling-period 10

        user-query-pattern (&(uid=${un})(|(objectclassName=inetOrgPerson)(objectclassName=posixAccount)))

    }

    log {

        report-violation true

    }

}
```

## LDAP debugging tips

### ldapsearch

When configuring LDAP in Aerospike, especially in writing your queries (filters in LDAP) it is helpful to have the full LDAP records for both a typical LDAP user and the groups to use for Aerospike roles.

One way to get this information is with `ldapsearch`.

Example `ldapsearch` queries

-   For a user:

```text
ldapsearch -w password -D CN=trusted_user,OU=ServiceAccount,DC=example,DC=com -b dc=example,dc=com -h ldap://ldap.example.com:389  '(uid=my_user)'
```

-   For a group:

```text
ldapsearch -w password -D CN=trusted_user,OU=ServiceAccout,DC=example,DC=com -b DC=example,DC=com -h ldap://ldap.example.com:389  '(CN=some_group)'
```

For other examples, see [Examples of Common ldapsearches](https://access.redhat.com/documentation/en-us/red_hat_directory_server/11/html/administration_guide/examples-of-common-ldapsearches).

If you have TLS enabled you must add your certs on the client machine and either an ldap.conf file must be created, or environment variables must be set. For more details, see [Using LDAP](https://www.openldap.org/doc/admin24/tls.html).

`ldapsearch` is also useful to test your query patterns. The pattern can be plugged directly to the earlier queries (replacing the `(CN=some_group)` in the above example) but with a value substituted in for the `${un}` placeholder.

For example, if you have a configuration like `role-query-pattern (&(objectclassName=posixGroup)(memberUid=${un}))` you can see if the query is valid for a perspective user with a uid of `joe_user` by issuing a command like:

```text
ldapsearch -w password -D CN=trusted_user,OU=ServiceAccout,DC=example,DC=com -b DC=example,DC=com -h ldap://ldap.example.com:389  '(&(objectclassName=posixGroup)(memberUid=joe_user))'
```

### Extra logging

You can turn on extra logging to see what role queries are being made for login, polling, and other verbose information. In the logging section of your configuration file, specify either of the following or both:

```text
console {

        context any critical

        context security detail

    }
```

or

```text
file FILENAME {

        context any critical

        context security detail

    }
```

To activate detailed security logging dynamically on a running system, run the following command:

::: note
[Tools package 6.0.x](https://aerospike.com/docs/database/tools/release-notes/#tools-603) or later is required to use asadm’s [`manage config`](https://aerospike.com/docs/database/tools/asadm/live-mode/#manage) commands. You can also use the equivalent [`asinfo - log-set`](https://aerospike.com/docs/database/reference/info#log-set).

```text
asadm -e 'enable; manage config logging file FILENAME param security to detail'
```
:::