<a id="kafka-ldap-config"></a>

<a id="configure-ldap-authorization"></a>

# Configure LDAP Group-Based Authorization in Confluent Platform

This topic includes descriptions of the LDAP configuration options available for
configuring group-based authorization.

## Configure LDAP context

All standard Java LDAP configurations are supported. Broker configurations starting with
`ldap.java.naming` and `ldap.com.sun.jndi` are stripped of their `ldap.` prefix
and these standard Java LDAP configurations are used to make connections to the LDAP server.
You must configure `ldap.java.naming.provider.url` with the URL of your LDAP server. For example:

```bash
ldap.java.naming.provider.url=ldap://somehost:389
```

For a complete list of standard Java configurations for the LDAP naming service
provider and Java Naming and Directory Interface (JNDI), see [LDAP Naming Service Provider for the
Java Naming and Directory Interface (JNDI)](https://docs.oracle.com/javase/8/docs/technotes/guides/jndi/jndi-ldap.html).

#### NOTE
Be aware that nested LDAP groups are not supported.

<a id="configure-multiple-ldap-servers"></a>

## Configure multiple LDAP servers

Confluent Platform supports configuring MDS with multiple LDAP servers from version 7.7 and
later. Instead of just one URL, you can also supply a space-separated list of
LDAP URLs. In this case, the LDAP provider attempts to use each URL in turn
until it is able to create a successful connection. This is useful for achieving
high availability of LDAP service in Confluent Platform. For example:

```properties
ldap.java.naming.provider.url=ldap://somehost:389 ldap://otherldaphost:389
```

<a id="configure-tls-for-ldap"></a>

## Configure TLS for LDAP

Enable TLS for the connections from the Confluent Server Authorizer to your LDAP server
by setting `ldap.java.naming.security.protocol=SSL`. LDAP provider
URL must use the protocol `ldaps` if TLS is enabled. All the TLS configuration
options of Kafka clients are supported and must be prefixed with `ldap.`.
For example:

```bash
# Configure provider URL with `ldaps` as protocol
ldap.java.naming.provider.url=ldaps://somehost:389
# Enable TLS for connections to LDAP server
ldap.java.naming.security.protocol=SSL
# Path of truststore for connections to LDAP
ldap.ssl.truststore.location=/path/to/truststore.jks
# Password of LDAP truststore
ldap.ssl.truststore.password=truststore-secret
```

For a list of supported TLS configurations, see [Encryption and Authentication with SSL](../../authentication/mutual-tls/overview.md#kafka-ssl-authentication).

#### NOTE
In Java 8 update 181 and later, host name verification is enabled by default
on LDAPS connections. You can disable this verification by setting
`KAFKA_OPTS=-Dcom.sun.jndi.ldap.object.disableEndpointIdentification=true`,
but you should avoid using this option in production systems. Prior to Java 8
update 181, host name verification was disabled by default for LDAPS
connections. For improved security, consider upgrading to Java 8 181 or later.

## Configure GSSAPI for LDAP

You can use GSSAPI to authenticate the Confluent Server Authorizer with your LDAP server if Kerberos
is enabled on your LDAP server. You can configure the JAAS configuration for GSSAPI
using the `ldap.sasl.jaas.config` configuration option. You must also configure
the authentication protocol and security principal using standard Java LDAP
configurations prefixed with `ldap.`. For example:

```bash
# Configure SASL/GSSAPI as the authentication protocol for LDAP context.
ldap.java.naming.security.authentication=GSSAPI
# Security principal for LDAP context
ldap.java.naming.security.principal=ldap@EXAMPLE.COM
# JAAS configuration for Kerberos authentication with LDAP server
ldap.sasl.jaas.config=com.sun.security.auth.module.Krb5LoginModule required \
  keyTab="/tmp/keytabs/ldap.keytab" \
  principal="ldap@EXAMPLE.COM" \
  storeKey="true" \
  useKeyTab="true";
```

#### NOTE
The [keytab](https://docs.oracle.com/cd/E19683-01/806-4078/6jd6cjs1l/index.html)
is a local file that stores the principal for LDAP, as well as a
timestamp, a key version number, and the encrypted keys. In this context,
`keyTab` is used to authenticate Kerberos with the LDAP server without having
to explicitly enter a password. You can view the principal in the keytab using
the `klist` command:

```bash
klist -kt /tmp/keytabs/ldap.keytab

#keytab content for LDAP principal
KVNO Timestamp         Principal
---- ----------------- ------------------------------------
   1 12/31/21 17:00:00 host/ldap@EXAMPLE.COM
```

If `ldap.sasl.jaas.config` is not configured, then the default JAAS configuration
of the broker will be used. The default JAAS configuration (the value specified in
the system property `java.security.auth.login.config`) is loaded from the login
context `KafkaServer` that is used as the broker’s login context using a single
shared login. You should use this configuration option for LDAP only if the
principal in this context can be used to search LDAP.

To test and perform basic troubleshooting on your LDAP client configuration when
configuring Kafka to authenticate to LDAP using Kerberos, refer to
[Testing and Troubleshooting LDAP Client Authentication](../../authentication/ldap/client-authentication-ldap.md#test-ldap-client-authentication).

## Configure password credentials for LDAP

If password authentication is enabled on your LDAP server, then you can configure
the user principal and password so that brokers can authenticate with the LDAP
server using simple authentication. Use standard Java configurations prefixed
with `ldap.` to configure LDAP credentials for the
broker. For example:

```bash
# Specify the LDAP security authentication protocol
ldap.java.naming.security.authentication=SIMPLE
# Identify the principal for the LDAP context
ldap.java.naming.security.principal=CN=Kafka Broker,OU=Users,DC=EXAMPLE,DC=COM
# Security credential is the password of the user that performs LDAP search
ldap.java.naming.security.credentials=broker-secret
```

## Configure LDAP search

To perform group-based authorization, brokers require a mapping of
the user principal. This mapping is determined during authentication
to group principals that define access rules.

You can configure broker search parameters so that your
LDAP server derives group principals for every user that connects to Confluent Platform.
The mapping can be derived from either user entries or group entries in LDAP by
configuring the search mode to use either `USERS` or `GROUPS`. You must
configure the search mode based on which entry contains both user and group
principals in the format used for authentication and authorization. You can
configure the LDAP attributes containing user and group principals in your LDAP
server entries, and regular expression patterns to extract the principal
from these attributes.

<a id="group-based-search-config"></a>

### Sample configuration for group-based search

By default, brokers read group entries from LDAP using group-based mode. If the
LDAP group entries in your LDAP server contain the user principal of members in
the format used to authenticate the principal by Confluent Server brokers, then you can use the
default group search.

For example, consider an LDAP server with a group entry that contains the
following attributes:

```bash
dn: CN=Kafka Developers,OU=Groups,DC=EXAMPLE,DC=COM
cn: kafkadev
objectClass: groupOfNames
member: UID=alice,OU=Users,DC=EXAMPLE,DC=COM
member: UID=bob,OU=Users,DC=EXAMPLE,DC=COM
```

If the user principals used by Kafka are `User:alice` and `User:bob`, then you
can configure the group-based search to map `User:alice` and `User:bob` to the group
principal `Group:kafkadev` using the following configuration:

#### NOTE
Once Kafka locates the list of users, it still needs to understand what a user
entry looks like in LDAP for the actual authentication. Thus, you must include
the `ldap.user.` configuration options even when search mode is set to `GROUPS`.

```bash
ldap.search.mode=GROUPS
# Required to ensure that Kafka can locate user entries in LDAP during authentication
ldap.user.search.base=<user-search-base-DN>
ldap.user.object.class=user
ldap.user.name.attribute=<sAMAccountName>
# Required for group-based search
ldap.group.search.base=DC=EXAMPLE,DC=COM
ldap.group.object.class=groupOfNames
ldap.group.name.attribute=cn
ldap.group.member.attribute=member
ldap.group.member.attribute.pattern=UID=(.*),OU=Users,DC=EXAMPLE,DC=COM
```

In some environments, the distinguished name (DN) of the user in the member entry may
not contain the principal generated by Confluent Server brokers during authentication. In
these cases, you can configure user-based search as described in the following
section.

<a id="user-based-search-config"></a>

### Sample configuration for user-based search

The user principal used for authorization by brokers is the principal generated
during authentication. For example, with Kerberos authentication using GSSAPI, the
default principal is the short name from the Kerberos principal. In some LDAP
environments, this principal may not appear in the `member` attribute of group
entries. In such cases, you can search in user mode to extract the principal
and group principals from LDAP user entries. This search mode provides the
flexibility required for most LDAP environments because group principals are
easily adapted to the format used in the user entry of your LDAP server.

For example, consider an LDAP server with a user entry containing the following
attributes:

```bash
objectClass: user
distinguishedName: CN=Joe Bloggs,CN=Users,DC=EXAMPLE,DC=COM
sAMAccountName: joe
memberOf: CN=Kafka Developers,CN=Users,DC=EXAMPLE,DC=COM
```

If the user principal used by Kafka is `User:joe` , then you can configure
group-based search to map `User:joe` to the group `Group:Kafka Developers`
using the following configuration:

```bash
ldap.search.mode=USERS
ldap.user.search.base=DC=EXAMPLE,DC=COM
ldap.user.object.class=user
ldap.user.name.attribute=sAMAccountName
ldap.user.memberof.attribute=memberOf
ldap.user.memberof.attribute.pattern=CN=(.*),CN=Users,.*
```

For LDAP servers with a large number of users where only a small subset access
Kafka, you can configure filters to limit the size of search results as described
in [Configure LDAP filters to limit search results](#ldap-filters-to-limit-search).

<a id="ldap-filters-to-limit-search"></a>

## Configure LDAP filters to limit search results

If you have a large number of users in the LDAP server, it is likely that
only a subset require access to Confluent Platform. In such instances, you can configure
filters to reduce the size of search results because brokers only require group
mapping for the small subset of users who connect to the Confluent Platform. LDAP filters are
particularly useful for user mode searches where you wish to avoid having
brokers process every user defined in the LDAP server.

You can configure a simple filter by adding all users accessing Confluent Platform to a group.
For example,  the following configuration filters out users belonging to
the Kafka group:

```bash
ldap.user.search.filter=(memberOf=CN=Kafka,CN=Users,DC=EXAMPLE,DC=COM)
```

You can also configure a simple filter that processes users belonging to a set of
groups when the users of the Confluent Platform already belong to a small set of
groups. For example, the following filter processes users belonging to the
groups `Administrators` and `Kafka Developers`:

```bash
ldap.user.search.filter=(|(memberOf=CN=Administrators,CN=Users,DC=EXAMPLE,DC=COM)(memberOf=CN=Kafka Developers,CN=Users,DC=example,DC=com))
```

If your LDAP server already has other attributes that match users or groups
connecting to Confluent Platform, you can filter based on those. You can use any valid
LDAP search filter to limit search results in both user and group search modes.

LDAP search filters do not use regex. Instead, LDAP search filters support
`'substring'` searches (which are not the same as wildcards)–not Regular
Expressions, which run on the LDAP server side rather than Confluent Platform. Examples of
valid substring LDAP search filters are: `'(uid=abc*)'`, and
`'(mail=`john@*.com')`)'`.

When specifying `memberOf` and `distinguishedName`, you must specify the full
DN (distinguished name) of the objects. For details about how to specify
the full DN when setting LDAP search filters while using Active Directory, refer
to [Active Directory: LDAP Syntax Filters](https://social.technet.microsoft.com/wiki/contents/articles/5392.active-directory-ldap-syntax-filters.aspx).

## Use persistent LDAP search

By default, the mapping of users to groups obtained from LDAP is refreshed periodically
with a refresh interval that you can configure using `ldap.refresh.interval.ms`.
If your LDAP server supports persistent search, you can set the refresh interval to zero
to initiate a persistent LDAP search in the Confluent Server Authorizer. LDAP updates are processed
as soon as notifications are received, enabling any changes to be used for authorization
immediately. Note that persistent search requires a connection to be kept open between
each broker and the LDAP server and may add load to your LDAP server.

```bash
ldap.refresh.interval.ms=0
```

#### IMPORTANT
Persistent search does not work with Java 17 and later. This is becauase Java 17
introduced certain enhanced encapsulation features that restrict reflective access
to internal classes. As a workaround, you can add the following as JVM argument
during startup:

```bash
--add-exports java.naming/com.sun.jndi.ldap=ALL-UNNAMED
```
