Summary: This article explains how to leverage existing LDAP groups for assigning roles to users in OpenSearch, building upon the previous article about LDAP user authentication. It details the process of configuring OpenSearch to authenticate users, fetch their LDAP groups, and map these groups to OpenSearch security roles, reducing user administration by utilizing the existing LDAP structure.
In the
last article, we explained how to use LDAP for user authentication in OpenSearch. Let’s explore how we can leverage existing LDAP groups for assigning roles to users. The following steps can of course also be applied to Active Directory.
Recap: User Authentication
Last time, we configured OpenSearch to connect to an LDAP server for user authentication. Since LDAP organises users (as well as any other objects) in a tree structure, we had to tell OpenSearch:
- In which LDAP subtree the users are stored
- How to query this subtree for a specific user
The query for looking up users contains a placeholder variable which is replaced with the user name before submission. If a user record was found and the password is correct, authentication is successful. We then mapped the user to a security role by user name.
Authorization: Leveraging LDAP groups
LDAP not only stores users but also groups: An LDAP user can be a member of one or more groups, and groups can also be nested (“group of groups”). So instead of assigning users directly to security roles, why not use the already existing LDAP groups? Doing so reduces the user administration by a great deal: You can add new LDAP users, assign them to LDAP groups, and the OpenSearch security roles will take effect automatically.
So we want OpenSearch to:
- First, verify that the user credentials are correct (authentication, “authc”)
- As a second step, fetch all LDAP groups of the authenticated user (authorization, “authz”)
In our example, we have two LDAP groups, “devops” and “qa”. LDAP groups are similar to users. Usually, they are stored in an LDAP subtree and are identified by their Distinguished Name. For example:
copydn: cn=devops,ou=groups,dc=example,dc=com
dn: cn=admin,ou=groups,dc=example,dc=com
Users are usually assigned to LDAP groups by the uniqueMember attributes, like:
copydn: cn=devops,ou=groups,dc=example,dc=com
uniqueMember: cn=Peter Scott,ou=people,dc=example,dc=com
uniqueMember: ...
dn: cn=qa,ou=groups,dc=example,dc=com
uniqueMember: cn=Peter Scott,ou=people,dc=example,dc=com
uniqueMember: ...
Our goal is to retrieve all LDAP groups a user is a member of and then map these groups to security roles.
Enabling LDAP Authorization
LDAP authorization is very similar to authentication. We need to tell OpenSearch:
- How to connect to LDAP
- In which subtree the roles are stored
- Which LDAP query we want to use for looking up the groups for a particular user
The authz section of config.yml defines the authorization backends. Lets add an authorization backend with type ldap and enable it:
copyconfig:
dynamic:
...
authc:
...
authz:
my_ldap_authenticator:
http_enabled: true
authorization_backend:
type: ldap
config:
...
Next, we need to define the connection settings. The possible values are identical to the
authc section discussed in our last article. Example:
copy authz:
my_ldap_authenticator:
http_enabled: true
authorization_backend:
type: ldap
config:
hosts:
- primary.ldap.example.com:389
- secondary.ldap.example.com:389
bind_dn: cn=admin,dc=example,dc=com
password: "password"
enable_ssl: true
pemtrustedcas_filepath: /full/path/to/trusted_cas.pem
Configuring the Roles Subtree and the Roles Query
Similar to authentication, we now need to tell OpenSearch where our LDAP roles are stored and what query should be used to look up all user groups.
copy authz:
my_ldap_authenticator:
...
authorization_backend:
...
config:
...
rolebase: 'ou=groups,dc=example,dc=com'
rolesearch: '(uniqueMember={0})'
The rolebase
parameter defines the LDAP groups subtree. As in the authc section, for the actual LDAP query (rolesearch
) we can use placeholders: The placeholder {0}
is replaced with the DN of the authenticated user.
So if this would be an SQL server instead of an LDAP server, the query would roughly look like this:
copySELECT * FROM ou=groups,dc=example,dc=com WHERE uniqueMember= '<DN of the authenticated user>'
Let’s have a look again at the example above. The user “Peter Scott” is a member of the LDAP group cn=devops,ou=groups,dc=example,dc=com
and cn=qa,ou=groups,dc=example,dc=com
. Executing the LDAP query would thus return both the devops and the qa LDAP group records.
Mapping LDAP Groups to OpenSearch Security Roles
We can now use these LDAP groups to assign OpenSearch security roles. This is done in roles_mapping.yml. Instead of specifying the usernames directly, this time use the LDAP groups retrieved in the authorization step:
role_mapping.yml:
copydevops_security_role:
backend_roles:
- "cn=devops,ou=groups,dc=example,dc=com"
qa_security_role:
backend_roles:
- "cn=qa,ou=groups,dc=example,dc=com"
This assigns the security role devops_security_role
to all users that are part of the cn=devops,ou=groups,dc=example,dc=com
LDAP group. All users in the LDAP group cn=qa,ou=groups,dc=example,dc=com
are assigned to the security role qa_security_role
.
We can now manage our users and their groups in our LDAP server, and do not need to touch the OpenSearch security configuration again. Mission accomplished!
Outlook
An LDAP directory structure can be quite complex, and there are many ways users and groups may be structured. Luckily, OpenSearch security supports a wide range of LDAP use cases. For example, OpenSearch can work with multiple LDAP servers, resolve nested groups, and also retrieve roles directly from an LDAP user record. We will discuss some of these in a follow-up article. Stay tuned!