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

# Configure LDAP Group-Based Authorization for MDS

#### IMPORTANT
The user ID specified in group role bindings is case-specific, and must match
the case specified in the AD record. Also note that when logging in as a super user,
the login ID is also case-specific and must match the case specified for the user
ID in role bindings.

## 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
```

Following are detailed descriptions of the required baseline JNDI LDAP
configuration options that Kafka uses to authenticate to the directory service
with the bind user.

`ldap.java.naming.provider.url`
: This option defines the URL to use for connections to the LDAP server. The
  default hostname is `localhost`; the default port is `389`. You must
  specify this option for the MDS configuration. To configure with multiple LDAP
  servers for high availability, you can also supply space-separated list of LDAP
  URLs.

`ldap.java.naming.security.authentication`
: If password authentication is enabled on your LDAP server, you can configure
  the user principal and password so that brokers can authenticate with the LDAP
  server using simple authentication. If you do not want to authenticate with the
  LDAP server, specify `none`. The recommended value to get your MDS
  up and running is `simple`, which is a PLAINTEXT authentication
  protocol and provides no security. For production instances, you should specify
  a more secure SASL method supported by your LDAP server (such as `SASL_GSSAPI`).

`ldap.java.naming.security.credentials`
: Specifies the security credentials (password) of the principal performing the LDAP
  search.

`ldap.java.naming.security.principal`
: Specifies the security principal, which is the distinguished name of the LDAP
  user performing the LDAP search. In this configuration, specify the
  MDS user using the DN (LDAP distinguished name, which is a sequence of relative
  distinguished names (RDN) connected by commas).

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).

<a id="configure-multiple-ldap-servers-for-mds"></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
```

### Configure multiple LDAP servers for FIPS deployment

If the FIPS deployment has multiple LDAP JNDI provider URLs configured, you must
specify the fully qualified domain name (FQDN) using the `ldap.fips.san.verification.fqdn`
configuration parameter. The FQDN is used to verify the hostname of LDAP servers.

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

## Configure TLS for LDAP

Enable TLS for the connections from the LDAP 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/SSL 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 [Use TLS Authentication in Confluent Platform](../../security/authentication/mutual-tls/overview.md#kafka-ssl-authentication).

## Configure GSSAPI for LDAP

You can use GSSAPI to authenticate the LDAP Authorizer with your LDAP server if Kerberos
is enabled on your LDAP server. The JAAS configuration for GSSAPI may be configured using
the configuration option `ldap.sasl.jaas.config`. Authentication protocol and security
principal must also be configured using standard Java LDAP configs 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";
```

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

## 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
# Configure simple LDAP binding for authentication
ldap.java.naming.security.authentication=SIMPLE
# Security principal is the distinguished name of the LDAP user that performs LDAP search
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.

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).

<a id="mds-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 Kafka 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 Kafka brokers during authentication. In
these cases, you can configure user-based search as described in the following
section.

<a id="mds-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](#mds-ldap-filters-to-limit-search).

<a id="mds-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.

#### IMPORTANT
Most LDAP clients, by default, limit the number of users returned in an LDAP
group to 1500 (this limit can vary between LDAP clients and servers). If you
have more than 1500 users in an LDAP group, you can configure filters that
limit the search results for users in the group, which can be an effective
way to work within or around size limits.

Also, check the documentation for your LDAP client or server to determine the
default limit for users returned in a group (and any configurable limits) and
to configure filters for your environment.

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.

## Using 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 LDAP 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
```

## LDAP Authorizer Configuration Options

### LDAP Search Configuration

`ldap.refresh.interval.ms`
: LDAP group cache refresh interval in milliseconds. If set to zero, then persistent LDAP search is used.
  <br/>
  * Type: int
  * Default: 60000
  * Importance: medium

`ldap.search.page.size`
: Page size for LDAP search if persistent search is disabled (in other words,
  when the refresh interval is greater than zero). Paging is disabled by default.
  <br/>
  * Type: int
  * Default: 0
  * Importance: medium

`ldap.search.mode`
: LDAP search mode that indicates if the user-to-group mapping is retrieved by
  searching for group or user entries. Valid values are USERS and GROUPS.
  <br/>
  * Type: string
  * Default: GROUPS
  * Valid Values: [GROUPS, USERS]
  * Importance: medium

### LDAP search by groups

`ldap.group.search.base`
: LDAP search base for group-based search.
  <br/>
  * Type: string
  * Default: ou=groups
  * Importance: high

`ldap.group.search.filter`
: LDAP search filter for group-based search.
  <br/>
  * Type: string
  * Default: “”
  * Importance: medium

`ldap.group.search.scope`
: LDAP search scope for group-based search. Valid values are 0 (OBJECT), 1 (ONELEVEL) and 2 (SUBTREE).
  <br/>
  * Type: int
  * Default: 1
  * Importance: medium

`ldap.group.object.class`
: LDAP object class for groups.
  <br/>
  * Type: string
  * Default: groupOfNames
  * Importance: medium

`ldap.group.name.attribute`
: Name of attribute that contains the name of the group in a group entry obtained using an LDAP search.
  A regex pattern may be specified to extract the group name used in ACLs from this attribute by
  configuring `ldap.group.name.attribute.pattern`.
  <br/>
  * Type: string
  * Default: cn
  * Importance: high

`ldap.group.name.attribute.pattern`
: A Java regular expression pattern that extracts the group name used in ACLs from the name of the group obtained
  from the LDAP attribute specified using  `ldap.group.name.attribute`. By default the full value of
  the attribute is used.
  <br/>
  * Type: string
  * Default: “”
  * Importance: low

`ldap.group.member.attribute`
: The name of the attribute that contains the members of the group in a group entry obtained using an LDAP search.
  A regex pattern may be specified to extract the user principals from this attribute by configuring
  `ldap.group.member.attribute.pattern`.
  <br/>
  * Type: string
  * Default: member
  * Importance: high

`ldap.group.member.attribute.pattern`
: A Java regular expression pattern that extracts the user principals of group members from group member
  entries obtained from the LDAP attribute specified using `ldap.group.member.attribute`.
  By default the full value of the attribute is used.
  <br/>
  * Type: string
  * Default: “”
  * Importance: medium

`ldap.group.dn.name.pattern`
: A Java regular expression pattern that extracts the group name from the distinguished
  name (DN) of the group when a group is renamed. This is used only when persistent search
  is enabled. By default the `ldap.group.name.attribute` is extracted from the DN.
  <br/>
  * Type: string
  * Default: “”
  * Importance: low

`ldap.user.dn.name.pattern`
: A Java regular expression pattern used to extract user name from the distinguished name (DN) of the user when
  user is renamed. This is used only when persistent search is enabled. By default
  `ldap.user.name.attribute` is extracted from the DN.
  <br/>
  * Type: string
  * Default: “”
  * Importance: low

### LDAP search by users

`ldap.user.search.base`
: The LDAP search base for a user-based search.
  <br/>
  * Type: string
  * Default: ou=users
  * Importance: medium

`ldap.user.search.filter`
: The LDAP search filter for a user-based search.
  <br/>
  * Type: string
  * Default: “”
  * Importance: medium

`ldap.user.search.scope`
: The LDAP search scope for a user-based search. Valid values are 0 (OBJECT), 1 (ONELEVEL), and 2 (SUBTREE).
  <br/>
  * Type: int
  * Default: 1
  * Importance: medium

`ldap.user.object.class`
: The LDAP object class for users.
  <br/>
  * Type: string
  * Default: person
  * Importance: medium

`ldap.user.name.attribute`
: Name of attribute that contains the user principal in a user entry obtained using an LDAP search. A regex pattern
  may be specified to extract the user principal from this attribute by configuring
  `ldap.user.name.attribute.pattern`.
  <br/>
  * Type: string
  * Default: uid
  * Importance: medium

`ldap.user.name.attribute.pattern`
: A Java regular expression pattern used to extract the user principal from the name of the user obtained from
  the LDAP attribute specified using `ldap.user.name.attribute`. By default the full value of the attribute is used.
  <br/>
  * Type: string
  * Default: “”
  * Importance: medium

`ldap.user.memberof.attribute`
: The name of the attribute that contains the groups in a user entry obtained
  using an LDAP search. A regex pattern may be specified to extract the group
  names used in ACLs from this attribute by configuring `ldap.user.memberof.attribute.pattern`.
  <br/>
  * Type: string
  * Default: memberof
  * Importance: medium

`ldap.user.memberof.attribute.pattern`
: A Java regular expression pattern used to extract the names of groups from user entries obtained from the
  LDAP attribute specified using  `ldap.user.memberof.attribute`. By default the full value
  of the attribute is used.
  <br/>
  * Type: string
  * Default: “”
  * Importance: medium

### Error Handling Configuration

`ldap.retry.backoff.ms`
: Initial retry backoff in milliseconds. Exponential backoff is used if `ldap.retry.backoff.max.ms` is set to a higher value.
  <br/>
  * Type: int
  * Default: 100
  * Importance: medium

`ldap.retry.backoff.max.ms`
: Maximum retry backoff in milliseconds. Exponential backoff is used if `ldap.retry.backoff.ms` is set to a lower value.
  <br/>
  * Type: int
  * Default: 1000
  * Importance: medium

`ldap.retry.timeout.ms`
: Timeout for LDAP search retries after which the LDAP Authorizer is marked as failed.
  All requests are denied access if a successful cache refresh cannot be performed
  within this time.
  <br/>
  * Type: long
  * Default: 86400000
  * Importance: medium

### TLS Configuration for LDAP connection

`ldap.ssl.protocol`
: The TLS protocol used to generate the SSLContext. The default is `TLSv1.3`
  when running with Java 11 or newer, `TLSv1.2` otherwise. This value should
  be fine for most use cases. Allowed values in recent JVMs are `TLSv1.2` and
  `TLSv1.3`. `TLS`, `TLSv1.1`, `SSL`, `SSLv2` and `SSLv3` might be
  supported in older JVMs, but their usage is discouraged due to known security
  vulnerabilities. With the default value for this configuration and `ssl.enabled.protocols`,
  clients downgrade to `TLSv1.2` if the server does not support `TLSv1.3`.
  If this configuration is set to `TLSv1.2`, clients do not use `TLSv1.3`,
  even if it is one of the values in `ssl.enabled.protocols` and the server
  only supports `TLSv1.3`.
  <br/>
  * Type: string
  * Default: `TLSv1.3`
  * Importance: medium

`ldap.ssl.provider`
: The name of the security provider used for TLS connections. The default value
  is the default security provider of the JVM.
  <br/>
  * Type: string
  * Default: null
  * Importance: medium

`ldap.ssl.enabled.protocols`
: The comma-separated list of protocols enabled for TLS connections. The default
  value is `TLSv1.2,TLSv1.3` when running with Java 11 or later, `TLSv1.2`
  otherwise. With the default value for Java 11 (`TLSv1.2,TLSv1.3`), Kafka
  clients and brokers prefer TLSv1.3 if both support it, and falls back to
  TLSv1.2 otherwise (assuming both support at least TLSv1.2).
  <br/>
  * Type: list
  * Default: `TLSv1.2,TLSv1.3`
  * Importance: medium

`ldap.ssl.keystore.type`
: The file format of the key store file. This attribute is optional for the client.
  <br/>
  * Type: string
  * Default: JKS
  * Importance: medium

`ldap.ssl.truststore.type`
: The file format of the trust store file.
  <br/>
  * Type: string
  * Default: JKS
  * Importance: medium

`ldap.ssl.key.password`
: The password of the private key in the key store file. This attribute is optional for client.
  <br/>
  * Type: password
  * Default: null
  * Importance: high

`ldap.ssl.keystore.location`
: The location of the key store file. This attribute is optional for the client and can be used for two-way client authentication.
  <br/>
  * Type: string
  * Default: null
  * Importance: high

`ldap.ssl.keystore.password`
: The store password for the key store file. This attribute is optional for the client and is only needed if `ssl.keystore.location` is configured.
  <br/>
  * Type: password
  * Default: null
  * Importance: high

`ldap.ssl.truststore.location`
: The location of the trust store file.
  <br/>
  * Type: string
  * Default: null
  * Importance: high

`ldap.ssl.truststore.password`
: The password for the trust store file. If a password is not set, then access to the truststore is still available,
  but integrity checking is disabled.
  <br/>
  * Type: password
  * Default: null
  * Importance: high

`ldap.ssl.cipher.suites`
: A list of cipher suites. This is a named combination of authentication,
  encryption, MAC and key exchange algorithm used to negotiate the security
  settings for a network connection using TLS. By default, all the available
  cipher suites are supported.
  <br/>
  * Type: list
  * Default: null
  * Importance: low

`ldap.ssl.keymanager.algorithm`
: The algorithm used by the key manager factory for TLS connections. The default
  value is the key manager factory algorithm configured for the Java Virtual Machine.
  <br/>
  * Type: string
  * Default: SunX509
  * Importance: low

`ldap.ssl.secure.random.implementation`
: The SecureRandom PRNG implementation to use for TLS cryptography operations.
  <br/>
  * Type: string
  * Default: null
  * Importance: low

`ldap.ssl.trustmanager.algorithm`
: The algorithm used by trust manager factory for TLS connections. The default
  value is the trust manager factory algorithm configured for the Java Virtual
  Machine.
  <br/>
  * Type: string
  * Default: PKIX
  * Importance: low

### SASL Configuration for LDAP connection

`ldap.sasl.jaas.config`
: JAAS login context parameters for SASL connections in the format used by JAAS configuration files. JAAS configuration
  file format is described in the [JAAS Login Configuration File documentation](https://docs.oracle.com/javase/8/docs/technotes/guides/security/jgss/tutorials/LoginConfigFile.html.).
  The format for the value is: `loginModuleClass controlFlag (optionName=optionValue)*;`.
  <br/>
  * Type: password
  * Default: null
  * Importance: medium

`ldap.sasl.login.callback.handler.class`
: The fully qualified name of a SASL login callback handler class that implements
  the AuthenticateCallbackHandler interface.
  <br/>
  * Type: class
  * Default: null
  * Importance: medium

`ldap.sasl.login.class`
: The fully qualified name of a class that implements the Login interface.
  <br/>
  * Type: class
  * Default: null
  * Importance: medium

`ldap.sasl.kerberos.kinit.cmd`
: The Kerberos kinit command path.
  <br/>
  * Type: string
  * Default: /usr/bin/kinit
  * Importance: low

`ldap.sasl.kerberos.min.time.before.relogin`
: The login thread sleep time between refresh attempts.
  <br/>
  * Type: long
  * Default: 60000
  * Importance: low

`ldap.sasl.kerberos.ticket.renew.jitter`
: Percentage of random jitter added to the renewal time.
  <br/>
  * Type: double
  * Default: 0.05
  * Importance: low

`ldap.sasl.kerberos.ticket.renew.window.factor`
: The duration that the login thread will sleep until the specified window factor of time from last refresh to ticket’s expiry has been reached,
  at which time it will try to renew the ticket.
  <br/>
  * Type: double
  * Default: 0.8
  * Importance: low
