How to Integrate Opensearch with LDAP for authentication and authorization

How to Integrate Opensearch with LDAP for authentication and authorization

opensearch_ldap_integration

Here in this article we will see how we can integrate LDAP service with Opensearch for authentication and authorization. We will be setting up an Opensearch cluster with LDAP configuration to connect to LDAP server for user authentication and create custom role with read only access and role mapping for user authorization.

Test Environment

Fedora Workstation 37
Docker
Docker Compose

What is LDAP server

LDAP server can be used for Authentication and Authorization services. Authentication is used to check whether the credentials entered by the user are valid and Authorization is used to check whether an user is allowed to carry out a particular action based on the permissions or roles (ie. set of permissions) that are mapped that user.

Let’s assume that you already have an secure LDAP server configured in your environment and try to integrate it with Opensearch Cluster.

If you are interested in watching the video. Here is the YouTube video on the same step by step procedure outlined below.

Procedure

Step1: Gather LDAP server details

As a first step let’s try to gather some of the important details about the LDAP server that we want to integrate with Opensearch cluster. These details can be secured from your LDAP server administrator in your organization.

Here are the sample details from my setup.

LDAP KeyLDAP value
hostnamefedser.stack.com
port636
ssl_enabledtrue
bind_dnCN=opensearch-stack,OU=Services,DC=stack,DC=com
bind_passwordxxx
user_baseDC=stack,DC=com
user_attributesThe user object entry attribute to use to carry out an LDAP query for searching that user
trusted_ca_certThe CA singer certificate of the LDAP server

For LDAP server CA signer certificate you can retrieve the details using the below openssl command and extract the issuer certificate and save it in a PEM file named “trusted_cas.pem”.

[admin@fedser awsopensearchldap]$ openssl s_client -showcerts -connect fedser.stack.com:636

Step2: Configure the LDAP Authentication section

LDAP authentication and authorization configuration is carried out in the following configuration file – “/usr/share/opensearch/config/opensearch-security/config.yml”. The authc and authz sections of the configuration are used for configuring the authentication and authorization settings respectively.

Here is the configuration for the authc section of LDAP.

The “authc” section is configured in such a way that when a user tries to authentication using their LDAP id from the Opensearch basic authentication page.
Connection is established with LDAP server based on the bind dn and password along with the ldap server and port details.
The LDAP id is passed as an input to the following “usersearch: ‘(sAMAccountName={0})'” where “0” is substituted with the LDAP id and an LDAP search is carried out in user base “userbase: ‘DC=stack,DC=com'”.
The username attribute to use from the user object entry is “username_attribute: cn” which is common name of the object is set here which is shown in the profile details on GUI.

[admin@fedser awsopensearchldap]$ cat config.yml
...
config:
  dynamic:
    authc:
    ...
      ldap:
        description: "Authenticate via LDAP or Active Directory"
        http_enabled: true
        transport_enabled: true
        order: 5
        http_authenticator:
          type: basic
          challenge: false
        authentication_backend:
          # LDAP authentication backend (authenticate users against a LDAP or Active Directory)
          type: ldap
          config:
            # enable ldaps
            enable_ssl: true
            # add trust ca file
            pemtrustedcas_filepath: /usr/share/opensearch/config/trusted_cas.pem
            # enable start tls, enable_ssl should be false
            enable_start_tls: false
            # send client certificate
            enable_ssl_client_auth: false
            # verify ldap hostname
            verify_hostnames: true
            hosts:
            - fedser.stack.com:636
            bind_dn: CN=opensearch-stack,OU=Services,DC=stack,DC=com
            password: xxx
            userbase: 'DC=stack,DC=com'
            # Filter to search for users (currently in the whole subtree beneath userbase)
            # {0} is substituted with the username
            usersearch: '(sAMAccountName={0})'
            # Use this attribute from the user as username (if not set then DN is used)
            username_attribute: cn

Step3: Configure the LDAP Authorization section

In this section we configure the authorization section of the LDAP. It contains the same details as authentication section as far as LDAP server connection and user search is concerned.
Once a user is authentication, the roles or the groups that this user is a member of are fetched using “rolesearch: ‘(member={0})'” where “0” is substituted with the LDAP id.
The role base “OU=opensearch_groups,DC=stack,DC=com” is used to match if any user role is a part of this role base and get the common name of the role “rolename: cn”.
Assume this role or group name is “ldapusergroup” which is present in the LDAP role base.

[admin@fedser awsopensearchldap]$ cat config.yml
...
config:
  dynamic:
    authc:
    ... update as above ...
    authz:
    ...
      ldap:
        description: "Authorize via LDAP or Active Directory"
        http_enabled: true
        transport_enabled: true
        authorization_backend:
          # LDAP authorization backend (gather roles from a LDAP or Active Directory, you have to configure the above LDAP authentication backend settings too)
          type: ldap
          config:
            # enable ldaps
            enable_ssl: true
            # add trust ca file
            pemtrustedcas_filepath: /usr/share/opensearch/config/trusted_cas.pem
            # enable start tls, enable_ssl should be false
            enable_start_tls: false
            # send client certificate
            enable_ssl_client_auth: false
            # verify ldap hostname
            verify_hostnames: true
            hosts:
            - fedser.stack.com:636
            bind_dn: CN=opensearch-stack,OU=Services,DC=stack,DC=com
            password: xxx
            rolebase: 'OU=opensearch_groups,DC=stack,DC=com'
            # Filter to search for roles (currently in the whole subtree beneath rolebase)
            # {0} is substituted with the DN of the user
            # {1} is substituted with the username
            # {2} is substituted with an attribute value from user's directory entry, of the authenticated user. Use userroleattribute to specify the name of the attribute
            rolesearch: '(member={0})'
            # Specify the name of the attribute which value should be substituted with {2} above
            userroleattribute: null
            # Roles as an attribute of the user entry
            userrolename: disabled
            #userrolename: memberOf
            # The attribute in a role entry containing the name of that role, Default is "name".
            # Can also be "dn" to use the full DN as rolename.
            rolename: cn
            # Resolve nested roles transitive (roles which are members of other roles and so on ...)
            resolve_nested_roles: true
            userbase: 'DC=stack,DC=com'
            # Filter to search for users (currently in the whole subtree beneath userbase)
            # {0} is substituted with the username
            #usersearch: '(uid={0})'
            #username_attribute: uid
            usersearch: '(sAMAccountName={0})'
            username_attribute: cn
            # Skip users matching a user name, a wildcard or a regex pattern
            #skip_users:
            #  - 'cn=Michael Jackson,ou*people,o=TEST'
            #  - '/\S*/'
            skip_users:
              - admin
              - kibanaserver

Step4: Update Docker Compose with LDAP configuration and LDAP CA cert file

Now that we are ready with the LDAP configuration, Here we are going to volume mount the LDAP configuration file and the trusted CA file containing the CA signer certificate of the LDAP server in the docker-compose.yml file as shown below.

[admin@fedser awsopensearchldap]$ cat docker-compose.yml 
version: '3'
services:
  opensearchldap-node1: # This is also the hostname of the container within the Docker network (i.e. https://opensearch-node1/)
    image: opensearchproject/opensearch:2.3.0 # Specifying the latest available image - modify if you want a specific version
    container_name: opensearchldap-node1
    environment:
      - cluster.name=opensearch-cluster # Name the cluster
      - node.name=opensearchldap-node1 # Name the node that will run in this container
      - discovery.seed_hosts=opensearchldap-node1,opensearchldap-node2 # Nodes to look for when discovering the cluster
      - cluster.initial_cluster_manager_nodes=opensearchldap-node1,opensearchldap-node2 # Nodes eligibile to serve as cluster manager
      - bootstrap.memory_lock=true # Disable JVM heap memory swapping
      - "OPENSEARCH_JAVA_OPTS=-Xms512m -Xmx512m" # Set min and max JVM heap sizes to at least 50% of system RAM
      - compatibility.override_main_response_version=true
    ulimits:
      memlock:
        soft: -1 # Set memlock to unlimited (no soft or hard limit)
        hard: -1
      nofile:
        soft: 65536 # Maximum number of open files for the opensearch user - set to at least 65536
        hard: 65536
    volumes:
      - opensearchldap-data1:/usr/share/opensearch/data # Creates volume called opensearch-data1 and mounts it to the container
      - ./config.yml:/usr/share/opensearch/config/opensearch-security/config.yml
      - ./trusted_cas.pem:/usr/share/opensearch/config/trusted_cas.pem
    ports:
      - 9200:9200 # REST API
      - 9600:9600 # Performance Analyzer
    networks:
      - opensearchldap-net # All of the containers will join the same Docker bridge network
  opensearchldap-node2:
    image: opensearchproject/opensearch:2.3.0 # This should be the same image used for opensearch-node1 to avoid issues
    container_name: opensearchldap-node2
    environment:
      - cluster.name=opensearch-cluster
      - node.name=opensearchldap-node2
      - discovery.seed_hosts=opensearchldap-node1,opensearchldap-node2
      - cluster.initial_cluster_manager_nodes=opensearchldap-node1,opensearchldap-node2
      - bootstrap.memory_lock=true
      - "OPENSEARCH_JAVA_OPTS=-Xms512m -Xmx512m"
      - compatibility.override_main_response_version=true
    ulimits:
      memlock:
        soft: -1
        hard: -1
      nofile:
        soft: 65536
        hard: 65536
    volumes:
      - opensearchldap-data2:/usr/share/opensearch/data
      - ./config.yml:/usr/share/opensearch/config/opensearch-security/config.yml
      - ./trusted_cas.pem:/usr/share/opensearch/config/trusted_cas.pem
    networks:
      - opensearchldap-net
  opensearchldap-dashboards:
    image: opensearchproject/opensearch-dashboards:2.3.0 # Make sure the version of opensearch-dashboards matches the version of opensearch installed on other nodes
    container_name: opensearchldap-dashboards
    ports:
      - 5601:5601 # Map host port 5601 to container port 5601
    expose:
      - "5601" # Expose port 5601 for web access to OpenSearch Dashboards
    environment:
      OPENSEARCH_HOSTS: '["https://opensearchldap-node1:9200","https://opensearchldap-node2:9200"]' # Define the OpenSearch nodes that OpenSearch Dashboards will query
    networks:
      - opensearchldap-net

volumes:
  opensearchldap-data1:
  opensearchldap-data2:

networks:
  opensearchldap-net:

Step5: Start the Opensearch Cluster with LDAP configuration

Let’s start up the Opensearch CLuster with LDAP configuration and ensure that is up and running.

[admin@fedser awsopensearchldap]$ docker-compose up -d

You can login to Opensearch Dashboard using the default internal user credentials (ie. admin/admin).

LDAP authentication and authorization domain will be shown as enabled as shown in below screenshot.

Step6: Create a Generic User Role for read access

Here in this step we are going to create a “genericaccess.json” file containing the permissions that we want to grant at the cluster, index and tenant level as shown below.
As you can see we are providing the permissions for a read only access to the Opensearch cluster at all these three levels.

[admin@fedser awsopensearchldap]$ cat genericaccess.json 
{
  "cluster_permissions": [
    "cluster_composite_ops_ro"
  ],
  "index_permissions": [{
    "index_patterns": [
      "*"
    ],
    "dls": "",
    "fls": [],
    "masked_fields": [],
    "allowed_actions": [
	    "read"
    ]
  }],
  "tenant_permissions": [{
    "tenant_patterns": [
      "*"
    ],
    "allowed_actions": [
      "kibana_all_read"
    ]
  }]
}

Let’s create this role as shown below using the REST API call.

[admin@fedser awsopensearchldap]$ curl -X PUT -H 'Content-Type: application/json' https://localhost:9200/_plugins/_security/api/roles/genericaccess -d @genericaccess.json -u admin:admin --insecure
{"status":"OK","message":"'genericaccess' created."}

Step7: Map Generic User Role to backend roles

Here in this step we are going to map the LDAP role that the user is a part of (ie. ldapusergroup) with the backend_roles and map these backend_roles to the role “genericaccess” which we created in earlier step. So backend roles can be anything like custom roles “ie. opensearch_dashboards_user, opensearch_dashboards_read_only” or roles fetched from the LDAP server (ie. ldapusergroup).

Map genericaccess role to backend roles as shown below.

[admin@fedser awsopensearchldap]$ curl -X PUT -H 'Content-Type: application/json' https://localhost:9200/_plugins/_security/api/rolesmapping/genericaccess -d '{ "backend_roles" : [ "ldapusergroup", "opensearch_dashboards_user", "opensearch_dashboards_read_only" ] }' -u admin:admin --insecure
{"status":"OK","message":"'genericaccess' created."}

Step8: Validate LDAP user authentication and authorization

Once the role and role mapping is completed. You can login with your LDAP credentails and validate that you have only read only access to the Opensearch Cluster. You can Login to the Opensearch Dashboard portal and verify the access.

URL – http://localhost:5601/

Hope you enjoyed reading this article. Thank you..