Active Directory and LDAP

    In most cases, you want to configure both authentication and authorization. You can also use authentication only and map the users retrieved from LDAP directly to Security plugin roles.

    We provide a fully functional example that can help you understand how to use an LDAP server for both authentication and authorization.

    1. Download and unzip .
    2. At the command line, run docker-compose up.
    3. Review the files:

      • docker-compose.yml defines a single OpenSearch node, an LDAP server, and a PHP administration tool for the LDAP server.

        You can access the administration tool at https://localhost:6443. Acknowledge the security warning and log in using cn=admin,dc=example,dc=org and changethis.

      • directory.ldif seeds the LDAP server with three users and two groups.

        psantos is in the Administrator and Developers groups. jroe and jdoe are in the Developers group. The Security plugin loads these groups as backend roles.

      • roles_mapping.yml maps the Administrator and Developers LDAP groups (as backend roles) to security roles so that users gain the appropriate permissions after authenticating.

      • internal_users.yml removes all default users except administrator and kibanaserver.

      • config.yml includes all necessary LDAP settings.

    4. Index a document as psantos:

      If you try the same request as jroe, it fails. The Developers group is mapped to the readall, manage_snapshots, and kibana_user roles and has no write permissions.

    5. Search for the document as jroe:

      1. curl -XGET 'https://localhost:9200/new-index/_search?pretty' -u 'jroe:password' -k

      This request succeeds, because the Developers group is mapped to the readall role.

    6. If you want to examine the contents of the various containers, run docker ps to find the container ID and then docker exec -it <container-id> /bin/bash.

    To enable LDAP authentication and authorization, add the following lines to config/opensearch-security/config.yml:

    1. authc:
    2. ldap:
    3. http_enabled: true
    4. transport_enabled: true
    5. order: 1
    6. http_authenticator:
    7. type: basic
    8. challenge: false
    9. authentication_backend:
    10. type: ldap
    11. config:
    12. ...
    1. authz:
    2. ldap:
    3. http_enabled: true
    4. transport_enabled: true
    5. authorization_backend:
    6. type: ldap
    7. config:
    8. ...

    The connection settings are identical for authentication and authorization and are added to the config sections.

    To configure the hostname and port of your Active Directory servers, use the following:

    1. config:
    2. hosts:
    3. - primary.ldap.example.com:389
    4. - secondary.ldap.example.com:389

    You can configure more than one server here. If the Security plugin cannot connect to the first server, it tries to connect to the remaining servers sequentially.

    Timeouts

    To configure connection and response timeouts to your Active Directory server, use the following (values are in milliseconds):

    1. config:
    2. connect_timeout: 5000
    3. response_timeout: 0

    If your server supports two-factor authentication (2FA), the default timeout settings might result in login errors. You can increase connect_timeout to accommodate the 2FA process. Setting response_timeout to 0 (the default) indicates an indefinite waiting period.

    Bind DN and password

    1. config:
    2. bind_dn: cn=admin,dc=example,dc=com
    3. password: password

    If your server supports anonymous authentication, both bind_dn and password can be set to null.

    TLS settings

    Use the following parameters to configure TLS for connecting to your server:

    1. config:
    2. enable_ssl: <true|false>
    3. enable_start_tls: <true|false>
    4. enable_ssl_client_auth: <true|false>
    5. verify_hostnames: <true|false>

    Certificate validation

    By default, the Security plugin validates the TLS certificate of the LDAP servers against the root CA configured in opensearch.yml, either as a PEM certificate or a truststore:

    1. plugins.security.ssl.transport.pemtrustedcas_filepath: ...
    2. plugins.security.ssl.http.truststore_filepath: ...

    If your server uses a certificate signed by a different CA, import this CA into your truststore or add it to your trusted CA file on each node.

    You can also use a separate root CA in PEM format by setting one of the following configuration options:

    1. config:
    2. pemtrustedcas_filepath: /full/path/to/trusted_cas.pem
    1. config:
    2. pemtrustedcas_content: |-
    3. MIID/jCCAuagAwIBAgIBATANBgkqhkiG9w0BAQUFADCBjzETMBEGCgmSJomT8ixk
    4. ARkWA2NvbTEXMBUGCgmSJomT8ixkARkWB2V4YW1wbGUxGTAXBgNVBAoMEEV4YW1w
    5. bGUgQ29tIEluYy4xITAfBgNVBAsMGEV4YW1wbGUgQ29tIEluYy4gUm9vdCBDQTEh
    6. ...
    NameDescription
    pemtrustedcas_filepathAbsolute path to the PEM file containing the root CAs of your Active Directory/LDAP server.
    pemtrustedcas_contentThe root CA content of your Active Directory/LDAP server. Cannot be used when pemtrustedcas_filepath is set.

    Client authentication

    If you use TLS client authentication, the Security plugin sends the PEM certificate of the node, as configured in opensearch.yml. Set one of the following configuration options:

    1. config:
    2. pemkey_filepath: /full/path/to/private.key.pem
    3. pemkey_password: private_key_password
    4. pemcert_filepath: /full/path/to/certificate.pem

    or

    You can limit the allowed ciphers and TLS protocols for the LDAP connection. For example, you can allow only strong ciphers and limit the TLS versions to the most recent ones:

    1. ldap:
    2. http_enabled: true
    3. transport_enabled: true
    4. ...
    5. authentication_backend:
    6. type: ldap
    7. config:
    8. enabled_ssl_ciphers:
    9. - "TLS_DHE_RSA_WITH_AES_256_CBC_SHA"
    10. - "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256"
    11. enabled_ssl_protocols:
    12. - "TLSv1.1"
    13. - "TLSv1.2"
    NameDescription
    enabled_ssl_ciphersArray, enabled TLS ciphers. Only the Java format is supported.
    Array, enabled TLS protocols. Only the Java format is supported.

    To use Active Directory/LDAP for authentication, first configure a respective authentication domain in the authc section of config/opensearch-security/config.yml:

    1. ldap:
    2. http_enabled: true
    3. transport_enabled: true
    4. order: 1
    5. http_authenticator:
    6. type: basic
    7. challenge: true
    8. authentication_backend:
    9. type: ldap
    10. config:
    11. ...

    Next, add the connection settings for your Active Directory/LDAP server to the config section of the authentication domain:

    1. config:
    2. enable_ssl: true
    3. enable_start_tls: false
    4. enable_ssl_client_auth: false
    5. verify_hostnames: true
    6. hosts:
    7. - ldap.example.com:8389
    8. bind_dn: cn=admin,dc=example,dc=com
    9. password: passw0rd

    Authentication works by issuing an LDAP query containing the user name against the user subtree of the LDAP tree.

    The Security plugin first takes the configured LDAP query and replaces the placeholder {0} with the user name from the user’s credentials.

    1. usersearch: '(sAMAccountName={0})'

    Then it issues this query against the user subtree. Currently, the entire subtree under the configured userbase is searched:

    1. userbase: 'ou=people,dc=example,dc=com'

    If the query is successful, the Security plugin retrieves the user name from the LDAP entry. You can specify which attribute from the LDAP entry the Security plugin should use as the user name:

    1. username_attribute: uid

    If this key is not set or null, then the distinguished name (DN) of the LDAP entry is used.

    Configuration summary

    Complete authentication example

    1. ldap:
    2. http_enabled: true
    3. transport_enabled: true
    4. order: 1
    5. http_authenticator:
    6. type: basic
    7. challenge: true
    8. authentication_backend:
    9. type: ldap
    10. config:
    11. enable_ssl: true
    12. enable_start_tls: false
    13. enable_ssl_client_auth: false
    14. verify_hostnames: true
    15. hosts:
    16. - ldap.example.com:636
    17. bind_dn: cn=admin,dc=example,dc=com
    18. password: password
    19. userbase: 'ou=people,dc=example,dc=com'
    20. usersearch: '(sAMAccountName={0})'
    21. username_attribute: uid

    To use Active Directory/LDAP for authorization, first configure a respective authorization domain in the authz section of config.yml:

    1. authz:
    2. ldap:
    3. http_enabled: true
    4. transport_enabled: true
    5. authorization_backend:
    6. type: ldap
    7. config:
    8. ...

    Authorization is the process of retrieving backend roles for an authenticated user from an LDAP server. This is typically the same servers that you use for authentication, but you can also use a different server. The only requirement is that the user you use to fetch the roles actually exists on the LDAP server.

    Because the Security plugin always checks if a user exists in the LDAP server, you must also configure userbase, usersearch and username_attribute in the authz section.

    Authorization works similarly to authentication. The Security plugin issues an LDAP query containing the user name against the role subtree of the LDAP tree.

    As an alternative, the Security plugin can also fetch roles that are defined as a direct attribute of the user entry in the user subtree.

    Approach 1: Query the role subtree

    The Security plugin first takes the LDAP query for fetching roles (“rolesearch”) and substitutes any variables found in the query. For example, for a standard Active Directory installation, you would use the following role search:

    1. rolesearch: '(member={0})'
    • {0} is substituted with the DN of the user.
    • {1} is substituted with the user name, as defined by the username_attribute setting.
    • {2} is substituted with an arbitrary attribute value from the authenticated user’s directory entry.

    The variable {2} refers to an attribute from the user’s directory entry. The attribute that you should use is specified by the userroleattribute setting:

    1. userroleattribute: myattribute

    The Security plugin then issues the substituted query against the configured role subtree. The entire subtree under rolebase is searched:

    1. rolebase: 'ou=groups,dc=example,dc=com'

    If you use nested roles (roles that are members of other roles), you can configure the Security plugin to resolve them:

    After all roles have been fetched, the Security plugin extracts the final role names from a configurable attribute of the role entries:

    1. rolename: cn

    If this is not set, the DN of the role entry is used. You can now use this role name for mapping it to one or more of the Security plugin roles, as defined in roles_mapping.yml.

    Approach 2: Use a user’s attribute as the role name

    If you store the roles as a direct attribute of the user entries in the user subtree, you need to configure only the attribute name:

    1. userrolename: roles

    You can configure multiple attribute names:

    1. userrolename: roles, otherroles

    This approach can be combined with querying the role subtree. The Security plugin fetches the roles from the user’s role attribute and then executes the role search.

    If you don’t use or have a role subtree, you can disable the role search completely:

    1. rolesearch_enabled: false

    (Advanced) Control LDAP user attributes

    By default, the Security plugin reads all LDAP user attributes and makes them available for index name variable substitution and DLS query variable substitution. If your LDAP entries have a lot of attributes, you might want to control which attributes should be made available. The fewer the attributes, the better the performance.

    Note that this setting is made in the authentication authc section of the config.yml file.

    NameDescription
    custom_attr_allowlistString array. Specifies the LDAP attributes that should be made available for variable substitution.
    custom_attr_maxval_lenInteger. Specifies the maximum allowed length of each attribute. All attributes longer than this value are discarded. A value of 0 disables custom attributes altogether. Default is 36.

    Example:

    1. authc:
    2. ldap:
    3. http_enabled: true
    4. transport_enabled: true
    5. authentication_backend:
    6. type: ldap
    7. config:
    8. custom_attr_allowlist:
    9. - attribute1
    10. - attribute2
    11. custom_attr_maxval_len: 36
    12. ...

    If you are using multiple authentication methods, it can make sense to exclude certain users from the LDAP role lookup.

    Consider the following scenario for a typical OpenSearch Dashboards setup: All OpenSearch Dashboards users are stored in an LDAP/Active Directory server.

    However, you also have an OpenSearch Dashboards server user. OpenSearch Dashboards uses this user to manage stored objects and perform monitoring and maintenance tasks. You do not want to add this user to your Active Directory installation, but rather store it in the Security plugin internal user database.

    In this case, it makes sense to exclude the OpenSearch Dashboards server user from the LDAP authorization because we already know that there is no corresponding entry. You can use the skip_users configuration setting to define which users should be skipped. Wildcards and regular expressions are supported:

    1. skip_users:
    2. - kibanaserver
    3. - 'cn=Jane Doe,ou*people,o=TEST'
    4. - '/\S*/'

    (Advanced) Exclude roles from nested role lookups

    If the users in your LDAP installation have a large number of roles, and you have the requirement to resolve nested roles as well, you might run into performance issues.

    In most cases, however, not all user roles are related to OpenSearch and OpenSearch Dashboards. You might need only a couple of roles. In this case, you can use the nested role filter feature to define a list of roles that are filtered out from the list of the user’s roles. Wildcards and regular expressions are supported.

    This has an effect only if resolve_nested_roles is true:

    1. nested_role_filter:
    2. - 'cn=Jane Doe,ou*people,o=TEST'
    3. - ...

    Configuration summary

    Complete authorization example

    1. authz:
    2. ldap:
    3. http_enabled: true
    4. transport_enabled: true
    5. authorization_backend:
    6. type: ldap
    7. config:
    8. enable_ssl: true
    9. enable_start_tls: false
    10. enable_ssl_client_auth: false
    11. verify_hostnames: true
    12. hosts:
    13. - ldap.example.com:636
    14. bind_dn: cn=admin,dc=example,dc=com
    15. password: password
    16. usersearch: '(uid={0})'
    17. username_attribute: uid
    18. rolebase: 'ou=groups,dc=example,dc=com'
    19. rolesearch: '(member={0})'
    20. userroleattribute: null
    21. userrolename: none
    22. rolename: cn
    23. resolve_nested_roles: true
    24. skip_users:
    25. - kibanaserver
    26. - 'cn=Jane Doe,ou*people,o=TEST'
    27. - '/\S*/'

    (Advanced) Configuring multiple user and role bases

    To configure multiple user bases in the authc and/or authz section, use the following syntax:

    1. ...
    2. bind_dn: cn=admin,dc=example,dc=com
    3. password: password
    4. users:
    5. primary-userbase:
    6. base: 'ou=people,dc=example,dc=com'
    7. search: '(uid={0})'
    8. secondary-userbase:
    9. base: 'cn=users,dc=example,dc=com'
    10. search: '(uid={0})'
    11. username_attribute: uid
    12. ...

    Similarly, use the following setup to configure multiple role bases in the authz section:

    1. ...
    2. username_attribute: uid
    3. roles:
    4. primary-rolebase:
    5. base: 'ou=groups,dc=example,dc=com'
    6. search: '(uniqueMember={0})'
    7. secondary-rolebase:
    8. base: 'ou=othergroups,dc=example,dc=com'
    9. search: '(member={0})'
    10. userroleattribute: null
    11. ...

    Complete authentication and authorization with multiple user and role bases example:

    1. authc:
    2. ...
    3. ldap:
    4. http_enabled: true
    5. transport_enabled: true
    6. order: 1
    7. http_authenticator:
    8. type: basic
    9. challenge: true
    10. authentication_backend:
    11. type: ldap
    12. config:
    13. enable_ssl: true
    14. enable_start_tls: false
    15. enable_ssl_client_auth: false
    16. verify_hostnames: true
    17. hosts:
    18. - ldap.example.com:636
    19. bind_dn: cn=admin,dc=example,dc=com
    20. password: password
    21. users:
    22. primary-userbase:
    23. base: 'ou=people,dc=example,dc=com'
    24. search: '(uid={0})'
    25. secondary-userbase:
    26. base: 'cn=users,dc=example,dc=com'
    27. search: '(uid={0})'
    28. username_attribute: uid
    29. authz:
    30. ldap:
    31. http_enabled: true
    32. transport_enabled: true
    33. authorization_backend:
    34. type: ldap
    35. config:
    36. enable_ssl: true
    37. enable_start_tls: false
    38. enable_ssl_client_auth: false
    39. verify_hostnames: true
    40. hosts:
    41. - ldap.example.com:636
    42. bind_dn: cn=admin,dc=example,dc=com
    43. password: password
    44. users:
    45. primary-userbase:
    46. base: 'ou=people,dc=example,dc=com'
    47. search: '(uid={0})'
    48. secondary-userbase:
    49. base: 'cn=users,dc=example,dc=com'
    50. search: '(uid={0})'
    51. username_attribute: uid
    52. roles:
    53. primary-rolebase:
    54. base: 'ou=groups,dc=example,dc=com'
    55. search: '(uniqueMember={0})'
    56. secondary-rolebase:
    57. base: 'ou=othergroups,dc=example,dc=com'
    58. search: '(member={0})'
    59. userroleattribute: null
    60. userrolename: none
    61. rolename: cn