Skip to content

Commit d37b9f4

Browse files
committed
Configuring LDAP Authentication in OpenSearch blog post
From time to time, a question about LDAP setup appear on Slack. We setup LDAP some time ago and the process was a bit tedious, but in the process we learned to check step by step the configuration. Add a blog post that drive users into configuring LDAP authc / authz, give pointers about what is going on at each step and show how to check that each step is successful. Signed-off-by: Romain Tartière <[email protected]>
1 parent 6e31a01 commit d37b9f4

File tree

4 files changed

+248
-0
lines changed

4 files changed

+248
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,248 @@
1+
---
2+
layout: post
3+
title: Configuring LDAP Authentication in OpenSearch
4+
authors:
5+
- smortex
6+
date: 2023-12-14 14:20:00 -1000
7+
category:
8+
- technical-posts
9+
meta_keywords: ldap, authentication, authorization
10+
meta_description: Learn how to set up OpenSearch for LDAP authentication
11+
---
12+
13+
The OpenSearch Security plugin has support multiple authentication backends.
14+
In this article, we dive into the LDAP backend to authenticate and authorize users form an external directory such as OpenLDAP or Active Directory.
15+
16+
17+
## Manage configuration
18+
19+
The LDAP configuration of OpenSearch is stored in its indexes.
20+
It is seeded from the `opensearch-security/config.yml` configuration file on first start, but it is not updated automatically when the file is changed later on.
21+
In this guide we will use the `securityadmin.sh` script to update the configuration in OpenSearch, using the demo certificates.
22+
Please exercise caution when updating, doing a backup first is advised.
23+
24+
> **NOTE:**
25+
> The `securityadmin.sh` script is currently deprecated, but at the time of writing its successor is not available.
26+
> For this reason, this guide rely on this legacy script.
27+
28+
29+
### Backup configuration
30+
31+
Backup the currently active configuration to the `/tmp/config` directory with this command (assuming an installation on a Debian system):
32+
33+
```
34+
OPENSEARCH_JAVA_HOME=/usr/share/opensearch/jdk /usr/share/opensearch/plugins/opensearch-security/tools/securityadmin.sh \
35+
-cacert /etc/opensearch/root-ca.pem \
36+
-cert /etc/opensearch/kirk.pem \
37+
-key /etc/opensearch/kirk-key.pem \
38+
-backup /tmp/config
39+
```
40+
41+
### Update configuration
42+
43+
After editing the `opensearch-security/config.yml` configuration file, it must be injected into OpenSearch using the `securityadmin.sh` script:
44+
45+
```
46+
OPENSEARCH_JAVA_HOME=/usr/share/opensearch/jdk /usr/share/opensearch/plugins/opensearch-security/tools/securityadmin.sh \
47+
-cacert /etc/opensearch/root-ca.pem \
48+
-cert /etc/opensearch/kirk.pem \
49+
-key /etc/opensearch/kirk-key.pem \
50+
-cd /etc/opensearch/opensearch-security
51+
```
52+
53+
## Setup users in LDAP
54+
55+
The complete configuration of a directory is way beyond the scope of this article.
56+
Here we will focus on the structure of the directory used in this example and how it was set up using OpenLDAP.
57+
Other LDAP implementation can be used instead of OpenLDAP and they probably support similar features, so please refer to your particular LDAP software documentation to set up a directory that match your needs.
58+
59+
In this example, our directory has the following structure:
60+
61+
```
62+
dc=example,dc=com
63+
|-> ou=groups
64+
| |-> cn=users
65+
| `-> cn=admins
66+
|-> ou=people
67+
| |-> uid=alice
68+
| `-> uid=bob
69+
`-> ou=services
70+
`-> cn=opensearch
71+
```
72+
73+
Both *alice* and *bob* are in the *users* group, and only *alice* is in the *admins* group.
74+
Anonymous bind is not allowed, so we also have a service account *opensearch* which will be used to find users before authentication.
75+
76+
## Configure OpenSearch authentication
77+
78+
In order to authenticate users using our directory (verifying that users are who they say they are), we add a new entry in the `config.dynamic.authc` section of the `opensearch-security/config.yml` file:
79+
80+
```yaml
81+
config:
82+
# [...]
83+
dynamic:
84+
# [...]
85+
authc:
86+
# [...]
87+
example_ldap:
88+
description: "Authenticate using example.com LDAP"
89+
http_enabled: true
90+
transport_enabled: false
91+
order: 4
92+
http_authenticator:
93+
type: basic
94+
challenge: false
95+
authentication_backend:
96+
type: ldap
97+
config:
98+
# enable ldaps
99+
enable_ssl: false
100+
# enable start tls, enable_ssl should be false
101+
enable_start_tls: true
102+
# send client certificate
103+
enable_ssl_client_auth: false
104+
# verify ldap hostname
105+
verify_hostnames: true
106+
hosts:
107+
- ldap.example.com
108+
# Anonymous binding is not allowed, bind as opensearch
109+
bind_dn: cn=opensearch,ou=services,dc=example,dc=com
110+
password: secret
111+
# Base DN to search for users
112+
userbase: 'ou=people,dc=example,dc=com'
113+
# Filter to search for users (currently in the whole subtree beneath userbase)
114+
# {0} is substituted with the username
115+
usersearch: '(uid={0})'
116+
# Use this attribute from the user as username (if not set then DN is used)
117+
username_attribute: cn
118+
```
119+
120+
Refer to the [Active Directory and LDAP](https://opensearch.org/docs/latest/security/authentication-backends/ldap/) page of the Security plugin for details about the configuration.
121+
Here we connect to a directory using STARTTLS, bind as a specific user with a password, and find users by their *uid* and use their *cn* attribute as username.
122+
123+
After updating the configuration with `securityadmin.sh` (see above), you should be able to sign-in with any user of the LDAP directory.
124+
125+
For now, once signed-in, almost any action will result in a *permission denied* error because we have not configured permissions yet.
126+
If you cannot sign-in, check the OpenSearch logs for errors, update the configuration and retry.
127+
There is no point in continuing if you cannot sign-in at this stage.
128+
129+
## Inspect current permissions
130+
131+
When signed-in, you can check your roles and backend roles by clicking on your avatar in the top-right corner, and clicking on *View roles and identities*.
132+
A pop-up display *roles* and *backend roles*.
133+
134+
![Screenshot showing the "View roles and identities" link](/assets/media/blog-images/2023-12-14-configure-ldap-authentication/view_roles_and_identities.png){:class="img-centered"}
135+
136+
![Screenshot of the pop-up displaying roles (own\_index) and backend roles (none)](/assets/media/blog-images/2023-12-14-configure-ldap-authentication/roles_backend_roles.png){:class="img-centered"}
137+
138+
*Roles* give actual permissions.
139+
These permissions are managed using the Security plugin under Management, Security, Roles.
140+
There, *roles* are also mapped to *backend roles*, that is users belonging to a *backend role* belong to the mapped *role* and have the associated permissions.
141+
142+
*Backend roles* correspond to LDAP groups.
143+
144+
For now, we have not configured authorization in the Security plugin, as a consequence the user does not belong to any *backend role* and only belong to a single role: *own_index* which is automatically added to all users in the default configuration.
145+
146+
## Link roles and backend roles
147+
148+
We have two groups in our directory, *users*, and *admins*.
149+
All users are members of the *users* group, and administrators are also members of the *admins* group.
150+
For this simple example, we want all authenticated users to have a read-only access to everything, and administrators to have a read-write access to everything.
151+
152+
In order to do this, we must map the *users* backend role to the *readall* and *kibana\_users* roles, and the *admins* backend role to the *all_access* role.
153+
154+
While this can be conveniently done using the OpenSearch Dashboards user interface, changes will be lost if you update the configuration with `securityadmin.sh` in the future (what we will be doing in a next step).
155+
We will therefore edit `opensearch-security/roles_mapping.yml` to update the mappings to fit our needs:
156+
157+
```yaml
158+
all_access:
159+
reserved: false
160+
backend_roles:
161+
- "admin"
162+
- "admins" # <--- added
163+
description: "Maps admin to all_access"
164+
165+
kibana_user:
166+
reserved: false
167+
backend_roles:
168+
- "kibanauser"
169+
- "users" # <--- added
170+
description: "Maps kibanauser to kibana_user"
171+
172+
readall:
173+
reserved: false
174+
backend_roles:
175+
- "readall"
176+
- "users" # <--- added
177+
```
178+
179+
## Configure OpenSearch authorization
180+
181+
The last step consist in configuring OpenSearch authorization (verifying that users are permitted to do what they are trying to do).
182+
183+
In OpenSearch, this is done by looking-up the *backend roles* of users from the LDAP groups they belong to.
184+
For *authentication* we added a `config.dynamic.authc` entry above, now for *authorization* we will add a `config.dynamic.authz` entry into `opensearch-security/config.yml`.
185+
186+
The `config.dynamic.authc` and `config.dynamic.authz` entries have a lot in common (we use the same directory, so the connection settings are the same), and only differ in how the groups of an user must be gathered:
187+
188+
```yaml
189+
config:
190+
# [...]
191+
dynamic:
192+
# [...]
193+
authz:
194+
# [...]
195+
roles_from_exapmle_ldap:
196+
description: "Authorize using example.com LDAP"
197+
http_enabled: true
198+
transport_enabled: false
199+
authorization_backend:
200+
type: ldap
201+
config:
202+
# enable ldaps
203+
enable_ssl: false
204+
# enable start tls, enable_ssl should be false
205+
enable_start_tls: true
206+
# send client certificate
207+
enable_ssl_client_auth: false
208+
# verify ldap hostname
209+
verify_hostnames: true
210+
hosts:
211+
- ldap.example.com
212+
# Anonymous binding is not allowed, bind as opensearch
213+
bind_dn: cn=opensearch,ou=services,dc=example,dc=com
214+
password: secret
215+
# Base DN to search for roles
216+
rolebase: 'ou=groups,dc=example,dc=com'
217+
# Filter to search for roles (currently in the whole subtree beneath rolebase)
218+
# {0} is substituted with the DN of the user
219+
# {1} is substituted with the username
220+
# {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
221+
rolesearch: '(uniqueMember={0})'
222+
# Specify the name of the attribute which value should be substituted with {2} above
223+
userroleattribute: null
224+
# Roles as an attribute of the user entry
225+
userrolename: disabled
226+
#userrolename: memberOf
227+
# The attribute in a role entry containing the name of that role, Default is "name".
228+
# Can also be "dn" to use the full DN as rolename.
229+
rolename: cn
230+
# Resolve nested roles transitive (roles which are members of other roles and so on ...)
231+
resolve_nested_roles: true
232+
# Base DN to search for users
233+
userbase: 'ou=people,dc=example,dc=com'
234+
# Filter to search for users (currently in the whole subtree beneath userbase)
235+
# {0} is substituted with the username
236+
usersearch: '(uid={0})'
237+
```
238+
239+
After updating the configuration with `securityadmin.sh` (see above), signed-in users should have the expected roles and backend roles:
240+
241+
![Screenshot of the pop-up displaying roles (own\_index, kibana\_user, readall) and backend roles (users)](/assets/media/blog-images/2023-12-14-configure-ldap-authentication/roles_backend_roles2.png){:class="img-centered"}
242+
243+
244+
## Conclusion
245+
246+
In this article, we saw how to proceed to configure step by step LDAP authentication and authorization, checking it is working at each stage.
247+
248+
Now that this basic configuration is in place, you can set up your own roles with permissions that match your site policies, and map them to your own LDAP groups through role backends.
Loading
Loading

0 commit comments

Comments
 (0)