Вступление
Elasticsearch (ES) — это поисковая система, основанная на Lucene. Он предоставляет распределенную полнотекстовую поисковую систему с поддержкой нескольких арендаторов с веб-интерфейсом HTTP и JSON-документами без схемы.
Kibana — это плагин для визуализации данных с открытым исходным кодом для Elasticsearch. Он предоставляет возможности визуализации поверх содержимого, проиндексированного в кластере Elasticsearch. Пользователи могут создавать линейчатые, линейные и точечные графики или круговые диаграммы и карты поверх больших объемов данных.
Эти два продукта широко используются на рынке сегодня для анализа данных. Однако безопасность — это один из аспектов, который изначально не был встроен в продукт. Поскольку сегодня данные являются жизненно важным для любой организации, становится необходимым обеспечить безопасность Elasticsearch и Kibana. В этом сообщении мы рассмотрим один из способов, с помощью которого для них могут быть реализованы аутентификация, авторизация и шифрование.
Предположения
Учебное пособие предполагает следующее:
- MapR Sandbox работает
- Elasticsearch и Kibana были установлены и работают
Варианты, доступные для обеспечения безопасности Elasticsearch и Kibana
Самые популярные варианты обеспечения безопасности Elasticsearch и Kibana сравниваются в таблице ниже.
Shield — это плагин безопасности, разработанный той же компанией, которая разработала Elasticsearch. Это позволяет вам легко защитить эти данные с помощью имени пользователя и пароля, упрощая вашу архитектуру. Расширенные функции безопасности, такие как шифрование, управление доступом на основе ролей, IP-фильтрация и аудит, также доступны по мере необходимости.
NGINX — это веб-сервер с открытым исходным кодом. Он может выступать в качестве прокси-сервера и, помимо прочего, может выполнять балансировку нагрузки. В сочетании с LUA и внешними сценариями его можно использовать для защиты Elasticsearch и Kibana. Мы будем использовать этот подход в этом уроке.
Searchguard — это альтернатива Shield с открытым исходным кодом. Он обеспечивает практически все те же функции, что и Shield, за исключением некоторых функций, таких как аутентификация LDAP. Однако эти функции доступны в платном варианте.
ЩИТ | NGINX | SEARCHGUARD |
Плагин безопасности для Elasticsearch и Kibana от Elasticsearch. | NGINX (произносится как «движок х») — это веб-сервер. Он может выступать в качестве обратного прокси-сервера, балансировщика нагрузки и кэша HTTP. | Search Guard — это плагин Elasticsearch, который предлагает шифрование, аутентификацию и авторизацию. |
Имеет встроенную поддержку для:
|
Управление доступом на основе ролей реализовано с помощью модуля LUA. Аутентификация LDAP может быть реализована с использованием внешних программ. | В бесплатной версии нет поддержки аутентификации на основе LDAP или ведения журнала аудита. |
$ 1600 / год / кластер | Свободно. NGINX Plus — платная версия — $ 1900 / экземпляр |
Свободно. Коммерческая версия также доступна. |
Установка NGINX
NGINX — это веб-сервер с открытым исходным кодом, ориентированный на высокую производительность, параллелизм и низкий объем занимаемой памяти.
NGINX с самого начала был разработан с учетом роли прокси и поддерживает множество связанных директив и опций конфигурации. Мы будем использовать NGINX для настройки аутентификации и авторизации на основе LDAP.
OpenResty ™ — это полноценная веб-платформа, объединяющая стандартное ядро NGINX, LuaJIT, множество тщательно написанных библиотек Lua, множество высококачественных сторонних модулей NGINX и большинство их внешних зависимостей.
Используя преимущества различных хорошо разработанных функций NGINX, OpenResty эффективно превращает сервер NGINX в мощный сервер веб-приложений.
меры
- Загрузите последнюю версию OpenResty здесь:
http://openresty.org/en/download.html - Создайте и установите пакет, используя следующие команды:
010203040506070809101112
tar xvf openresty-.tar.gz
cd openresty-
./configure --prefix=/usr/local/openresty --with-luajit
--with-http_auth_request_module
gmake
gmake install
export PATH=/usr/local/openresty/bin:/usr/local/openresty/nginx/sbin:$PATH
Аутентификация
В этом руководстве мы рассмотрим следующие два метода аутентификации:
- Базовая HTTP-аутентификация
- Аутентификация LDAP
Базовая HTTP-аутентификация
Шаг 1 — Установка инструментов Apache
Вам потребуется команда htpassword для настройки пароля, который ограничит доступ к Elasticsearch и Kibana. Эта команда является частью пакета apache2-utils, поэтому первым шагом является установка этого пакета.
sudo apt-get install apache2-utils
Шаг 2. Настройка учетных данных для базовой аутентификации HTTP
На этом этапе вы создадите пароль для пользователя, которому должен быть разрешен доступ к Elasticsearch и Kibana. Этот пароль и соответствующее имя пользователя будут сохранены в указанном вами файле.
Пароль будет зашифрован, а имя файла может быть любым. Здесь мы используем файл /opt/elk/.espasswd
и имя пользователя vikash
.
Чтобы создать пароль, выполните следующую команду. Вам нужно будет пройти аутентификацию, затем указать и подтвердить пароль.
sudo htpasswd -c /opt/elk/.espasswd vikash
Вы можете проверить содержимое вновь созданного файла, чтобы увидеть имя пользователя и хешированный пароль.
cat /opt/elk/.espasswd
Шаг 3 — Обновление конфигурации NGINX
Теперь, когда вы создали учетные данные базовой аутентификации HTTP, следующим шагом является обновление конфигурации NGINX для Elasticsearch и Kibana, чтобы использовать ее.
Базовая аутентификация HTTP становится возможной благодаря директивам auth_basic
и auth_basic_user_file
.
Значением auth_basic является любая строка, которая будет отображаться в приглашении для аутентификации. Значение auth_basic_user_file — это путь к файлу паролей, который был создан на шаге 2. Обе директивы должны быть добавлены в раздел location.
Проверьте, запущены ли какие-либо процессы NGINX, и уничтожьте их:
1
2
3
4
5
6
7
|
cd /usr/local/openresty/nginx/ sbin/nginx -s stop (Or) ps –ef | grep nginx kill - 9 <pid1> <pid2> …. <pidn> |
Запустите сервер NGINX с этим файлом конфигурации, как показано ниже:
1
2
|
cd /usr/local/openresty/nginx sbin/nginx -p $PWD -c conf/nginx_basic_http_authentication.conf |
Содержание файла конфигурации приведено ниже:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
|
worker_processes 1 ; error_log /usr/local/openresty/nginx/logs/lua.log debug; events { worker_connections 1024 ; } http { upstream elasticsearch { server 127.0 . 0.1 : 9201 ; keepalive 15 ; } upstream kibana { server 127.0 . 0.1 : 5701 ; keepalive 15 ; } server { listen 8881 ; location / { auth_basic "Protected Elasticsearch" ;< auth_basic_user_file /opt/elk/.espasswd; proxy_pass http: //elasticsearch; proxy_redirect off; proxy_buffering off; proxy_http_version 1.1 ; proxy_set_header Connection "Keep-Alive" ; proxy_set_header Proxy-Connection "Keep-Alive" ; } } server { listen 8882 ; location / { auth_basic "Protected Kibana" ; auth_basic_user_file /opt/elk/.espasswd; proxy_pass http: //kibana; proxy_redirect off; proxy_buffering off; proxy_http_version 1.1 ; proxy_set_header Connection "Keep-Alive" ; proxy_set_header Proxy-Connection "Keep-Alive" ; } } } |
Ниже представлены скриншоты, когда пользователь пытается получить доступ к Elasticsearch.
Примечание: NGINX настроен на прослушивание порта 8881 для соединений с Elasticsearch и порта 8882 для соединений с Kibana в этом примере.
Снимки экрана, показывающие, что «evil_user» не имеет доступа к Elasticsearch
Поскольку пользователь не присутствует в файле паролей, он / она был снова перенаправлен на страницу входа.
Снимок экрана, показывающий, что пользователь ‘vikash’ имеет доступ к Elasticsearch
Аутентификация LDAP
Шаг 1. Если сервер LDAP еще не запущен, установите и настройте его. Для целей этого примера, пожалуйста, следуйте инструкциям на https://github.com/osixia/docker-openldap для настройки сервера LDAP.
Поскольку сервер LDAP работает в контейнере Docker, следующие команды будут полезны для перезапуска и выполнения административных задач с ним:
docker ps –a
— выводит список всех запущенных процессов Docker
docker exec -it <Docker PID> bash
— открывает оболочку bash на компьютере Docker
Шаг 2: В этом примере мы будем запускать внутренний сервер, написанный на Python, который обслуживает страницу входа в систему, и демон аутентификации LDAP, написанный на Python. Файлы кода Python доступны в этом репозитории GitHub:
https://github.com/nginxinc/nginx-ldap-auth
Шаг 3: На хосте, где должен запускаться демон ldap-auth, установите следующее дополнительное программное обеспечение. Мы рекомендуем использовать версии, распространяемые вместе с операционной системой, вместо загрузки программного обеспечения из репозитория с открытым исходным кодом.
- Версия Python 2. Версия 3 не поддерживается.
- Модуль Python LDAP, python-ldap (По проекту ОС python-ldap.org).
Шаг 4: Ниже представлен файл конфигурации NGINX Plus. Важные директивы обсуждаются здесь.
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
|
Filename - /usr/local/openresty/nginx/conf/conf/nginx-ldap-auth.conf error_log logs/error.log debug; error_log /usr/local/openresty/nginx/logs/lua.log notice; events { } http { proxy_cache_path cache/ keys_zone=auth_cache:10m; # The back-end daemon listens on port 9000 as implemented # in backend-sample-app.py. # Change the IP address if the daemon is not running on the # same host as NGINX/NGINX Plus. upstream backend { server 127.0 . 0.1 : 9000 ; } upstream elasticsearch { server 127.0 . 0.1 : 9200 ; } upstream kibana4 { server 127.0 . 0.1 : 5601 ; } # NGINX/NGINX Plus listen on port 8081 for requests that require # authentication. Change the port number as appropriate. server { listen 8881 ; # Protected application location / { auth_request /auth-proxy; # redirect 401 and 403 to login form error_page 401 403 = 200 /login; auth_request_set $user $upstream_http_LDAPUser; access_by_lua_file '/usr/local/openresty/nginx/authorize_es_ldap.lua' ; proxy_pass http: //elasticsearch/; } location /login { proxy_pass http: //backend/login; # Login service returns a redirect to the original URI # and sets the cookie for the ldap-auth daemon proxy_set_header X-Target $request_uri; } location = /auth-proxy { internal; # The ldap-auth daemon listens on port 8888 , as set # in nginx-ldap-auth-daemon.py. # Change the IP address if the daemon is not running on # the same host as NGINX/NGINX Plus. proxy_pass http: //127.0.0.1:8888; proxy_pass_request_body off; #proxy_set_header Content-Length "" ; proxy_cache auth_cache; proxy_cache_valid 200 403 10m; # The following directive adds the cookie to the cache key proxy_cache_key "$http_authorization$cookie_nginxauth" ; # As implemented in nginx-ldap-auth-daemon.py, the ldap-auth daemon # communicates with an OpenLDAP server, passing in the following # parameters to specify which user account to authenticate. To # eliminate the need to modify the Python code, this file contains # 'proxy_set_header' directives that set the values of the # parameters. Set or change them as instructed in the comments. # # Parameter Proxy header # ----------- ---------------- # basedn X-Ldap-BaseDN # binddn X-Ldap-BindDN # bindpasswd X-Ldap-BindPass # cookiename X-CookieName # realm X-Ldap-Realm # template X-Ldap-Template # url X-Ldap-URL # (Required) Set the URL and port for connecting to the LDAP server, # by replacing 'example.com' and '636' . proxy_set_header X-Ldap-URL "ldap://172.17.0.1:389" ; # (Required) Set the Base DN, by replacing the value enclosed in # double quotes. proxy_set_header X-Ldap-BaseDN "dc=example,dc=org" ; # (Required) Set the Bind DN, by replacing the value enclosed in # double quotes. proxy_set_header X-Ldap-BindDN "cn=admin,dc=example,dc=org" ; # (Required) Set the Bind password, by replacing 'secret' . proxy_set_header X-Ldap-BindPass "admin" ; # (Required) The following directives set the cookie name and pass # it, respectively. They are required for cookie-based # authentication. Comment them out if using HTTP basic # authentication. proxy_set_header X-CookieName "nginxauth" ; proxy_set_header Cookie nginxauth=$cookie_nginxauth; # (Required if using Microsoft Active Directory as the LDAP server) # Set the LDAP template by uncommenting the following directive. #proxy_set_header X-Ldap-Template "(SAMAccountName=%(username)s)" ; # (Optional if using OpenLDAP as the LDAP server) Set the LDAP # template by uncommenting the following directive and replacing # '(cn=%(username)s)' which is the default set in # nginx-ldap-auth-daemon.py. #proxy_set_header X-Ldap-Template "(cn=%(username)s)" ; # (Optional) Set the realm name, by uncommenting the following # directive and replacing 'Restricted' which is the default set # in nginx-ldap-auth-daemon.py. #proxy_set_header X-Ldap-Realm "Restricted" ; } } server { listen 8882 ; # Protected application location / { auth_request /auth-proxy; # redirect 401 and 403 to login form error_page 401 403 = 200 /login; auth_request_set $user $upstream_http_LDAPUser; access_by_lua_file '/usr/local/openresty/nginx/authorize_kibana4_ldap.lua' ; proxy_pass http: //kibana4/; } location /login { proxy_pass http: //backend/login; # Login service returns a redirect to the original URI # and sets the cookie for the ldap-auth daemon proxy_set_header X-Target $request_uri; } location = /auth-proxy { internal; # The ldap-auth daemon listens on port 8888 , as set # in nginx-ldap-auth-daemon.py. # Change the IP address if the daemon is not running on # the same host as NGINX/NGINX Plus. proxy_pass http: //127.0.0.1:8888; proxy_pass_request_body off; #proxy_set_header Content-Length "" ; proxy_cache auth_cache; proxy_cache_valid 200 403 10m; # The following directive adds the cookie to the cache key proxy_cache_key "$http_authorization$cookie_nginxauth" ; # As implemented in nginx-ldap-auth-daemon.py, the ldap-auth daemon # communicates with an OpenLDAP server, passing in the following # parameters to specify which user account to authenticate. To # eliminate the need to modify the Python code, this file contains # 'proxy_set_header' directives that set the values of the # parameters. Set or change them as instructed in the comments. # # Parameter Proxy header # ----------- ---------------- # basedn X-Ldap-BaseDN # binddn X-Ldap-BindDN # bindpasswd X-Ldap-BindPass # cookiename X-CookieName # realm X-Ldap-Realm # template X-Ldap-Template # url X-Ldap-URL # (Required) Set the URL and port for connecting to the LDAP server, # by replacing 'example.com' and '636' . proxy_set_header X-Ldap-URL "ldap://172.17.0.1:389" ; # (Required) Set the Base DN, by replacing the value enclosed in # double quotes. proxy_set_header X-Ldap-BaseDN "dc=example,dc=org" ; # (Required) Set the Bind DN, by replacing the value enclosed in # double quotes. proxy_set_header X-Ldap-BindDN "cn=admin,dc=example,dc=org" ; # (Required) Set the Bind password, by replacing 'secret' . proxy_set_header X-Ldap-BindPass "admin" ; # (Required) The following directives set the cookie name and pass # it, respectively. They are required for cookie-based # authentication. Comment them out if using HTTP basic # authentication. proxy_set_header X-CookieName "nginxauth" ; proxy_set_header Cookie nginxauth=$cookie_nginxauth; # (Required if using Microsoft Active Directory as the LDAP server) # Set the LDAP template by uncommenting the following directive. #proxy_set_header X-Ldap-Template "(SAMAccountName=%(username)s)" ; # (Optional if using OpenLDAP as the LDAP server) Set the LDAP # template by uncommenting the following directive and replacing # '(cn=%(username)s)' which is the default set in # nginx-ldap-auth-daemon.py. #proxy_set_header X-Ldap-Template "(cn=%(username)s)" ; # (Optional) Set the realm name, by uncommenting the following # directive and replacing 'Restricted' which is the default set # in nginx-ldap-auth-daemon.py. #proxy_set_header X-Ldap-Realm "Restricted" ; } } } |
Настройки LDAP
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
# URL and port for connecting to the LDAP server # Use “ldaps: //< IP Address of the LDAP Server >:636” if you are using secure LDAP proxy_set_header X-Ldap-URL "ldap://< IP Address of the LDAP Server > " ; # Base DN proxy_set_header X-Ldap-BaseDN "cn=admin,dc=example,dc=org" ; # Bind DN proxy_set_header X-Ldap-BindDN "cn=admin,dc=example,dc=org" ; # Bind password proxy_set_header X-Ldap-BindPass "admin" ; IP Address for Backend Daemon If the backend daemon is not running on the same host as NGINX Plus, change the IP address for it in the upstream configuration block: upstream backend { server 127.0 . 0.1 : 9000 ; } IP Address for ldap-auth Daemon If the ldap-auth daemon is not running on the same host as NGINX Plus, change the IP address in this proxy_pass directive: location = /auth-proxy { proxy_pass http: //127.0.0.1:8888; ... } IP Address and Port on Which NGINX Listens If the client is not running on the same host as NGINX Plus, change the IP address in this listen directive (or remove the address completely to accept traffic from any client). You can also change the port on which NGINX listens from 8081 if you wish: server { listen 127.0 . 0.1 : 8081 ; … } |
Примечание. Elasticsearch работает на порту 9200, а NGINX прослушивает соединения с Elasticsearch на порту 8081.
Шаг 5: Запустите сервер NGINX, серверную часть и демон аутентификации LDAP:
Проверьте, запущен ли какой-либо процесс сервера NGINX, и убейте их:
1
2
3
4
5
6
7
|
cd /usr/local/openresty/nginx/ sbin/nginx -s stop (Or) ps –ef | grep nginx kill - 9 <pid1> <pid2> …. <pidn> |
Запустите сервер NGINX с соответствующим файлом конфигурации:
1
2
|
cd /usr/local/openresty/nginx/ sbin/nginx -p $PWD -c conf/nginx-ldap-auth.conf |
Запустите внутренний сервер:
1
2
|
cd /usr/local/openresty/nginx-ldap-auth python backend-sample-app.py |
Запустите демон аутентификации LDAP:
1
2
|
cd /usr/local/openresty/nginx-ldap-auth python nginx-ldap-auth-daemon.py |
Ниже приведены снимки экрана, на которых показаны выходные данные сервера, демона аутентификации LDAP и браузера, пытающегося получить доступ к Elasticsearch.
- Попытка получить доступ к Elasticsearch с недействительными учетными данными
- Демон аутентификации LDAP, показывающий ошибку аутентификации (перетащите изображение в нижний угол, чтобы получить более четкое представление).
- Попытка получить доступ к Elasticsearch, предоставив действительные учетные данные
- Веб-браузер перенаправляется в Elasticsearch после успешной аутентификации
- Аутентификация LDAP для запросов CURL
авторизация
Мы покажем, как реализовать следующие методы авторизации:
- Контроль доступа на основе скриптов LUA
- Многоуровневая безопасность для разных экземпляров Elasticsearch / Kibana
Контроль доступа с помощью скриптов LUA
Директива access_by_lua_file в файле конфигурации NGINX используется для указания пути к файлу LUA, который контролирует доступ к определенному ресурсу в Elasticsearch.
Ниже приведен пример сценария LUA, который показывает, как разрешить только пользователю «vikash» доступ к индексу «Traffic» и ограничить пользователя «swapnil»
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
|
-- authorization rules local restrictions = { all = { [ "^/$" ] = { "HEAD" } }, swapnil = { [ "^/$" ] = { "GET" }, [ "^/?[^/]*/?[^/]*/_search" ] = { "GET" , "POST" }, [ "^/?[^/]*/?[^/]*/_msearch" ] = { "GET" , "POST" }, [ "^/?[^/]*/?[^/]*/_validate/query" ] = { "GET" , "POST" }, [ "/_aliases" ] = { "GET" }, [ "/_cluster.*" ] = { "GET" } }, vikash = { [ "^/$" ] = { "GET" }, [ "^/?[^/]*/?[^/]*/_search" ] = { "GET" , "POST" }, [ "^/?[^/]*/?[^/]*/_msearch" ] = { "GET" , "POST" }, [ "^/?[^/]*/traffic*" ] = { "GET" , "POST" , "PUT" , "DELETE" }, [ "^/?[^/]*/?[^/]*/_validate/query" ] = { "GET" , "POST" }, [ "/_aliases" ] = { "GET" }, [ "/_cluster.*" ] = { "GET" } }, admin = { [ "^/?[^/]*/?[^/]*/_bulk" ] = { "GET" , "POST" }, [ "^/?[^/]*/?[^/]*/_refresh" ] = { "GET" , "POST" }, [ "^/?[^/]*/?[^/]*/?[^/]*/_create" ] = { "GET" , "POST" }, [ "^/?[^/]*/?[^/]*/?[^/]*/_update" ] = { "GET" , "POST" }, [ "^/?[^/]*/?[^/]*/?.*" ] = { "GET" , "POST" , "PUT" , "DELETE" }, [ "^/?[^/]*/?[^/]*$" ] = { "GET" , "POST" , "PUT" , "DELETE" }, [ "/_aliases" ] = { "GET" , "POST" } } } -- get authenticated user as role local role = ngx.var.remote_user ngx.log(ngx.DEBUG, role) -- exit 403 when no matching role has been found if restrictions[role] == nil then ngx.header.content_type = 'text/plain' ngx.log(ngx.WARN, "Unknown role [" ..role.. "]" ) ngx.status = 403 ngx.say( "403 Forbidden: You don\'t have access to this resource." ) return ngx.exit( 403 ) end -- get URL local uri = ngx.var.uri ngx.log(ngx.DEBUG, uri) -- get method local method = ngx.req.get_method() ngx.log(ngx.DEBUG, method) local allowed = false for path, methods in pairs(restrictions[role]) do -- path matched rules? local p = string.match(uri, path) local m = nil -- method matched rules? for _, _method in pairs(methods) do m = m and m or string.match(method, _method) end if p and m then allowed = true ngx.log(ngx.NOTICE, method.. " " ..uri.. " matched: " ..tostring(m).. " " ..tostring(path).. " for " ..role) break end end if not allowed then ngx.header.content_type = 'text/plain' ngx.log(ngx.WARN, "Role [" ..role.. "] not allowed to access the resource [" ..method.. " " ..uri.. "]" ) ngx.status = 403 ngx.say( "403 Forbidden: You don\'t have access to this resource." ) return ngx.exit( 403 ) end |
1
2
3
4
5
6
7
|
cd /usr/local/openresty/nginx/ sbin/nginx -s stop (Or) ps –ef | grep nginx kill - 9 <pid1> <pid2> …. <pidn> |
Запустите службу NGINX с этими конфигурациями:
1
2
|
cd /usr/local/openresty/nginx/ sbin/nginx -p $PWD -c conf/nginx_authorize_by_lua.conf |
Снимки экрана, на которых показан отказ в доступе к индексу «трафика» для пользователя «swapnil»
Снимки экрана, на которых пользователь swapnil может получить доступ к другим ресурсам, кроме «трафика»
Снимок экрана, показывающий, что пользователь ‘vikash’ имеет доступ к индексу «трафика»
Многоуровневая безопасность (MLS)
Проблема с вышеуказанным подходом состоит в том, что мы не можем повторить этот процесс для Кибаны. Kibana получает все свои данные от Elasticsearch и переписывает все URL-адреса внутри, поэтому мы больше не знаем, что такое URL-адреса, и, следовательно, не можем писать для них правила.
В подобных ситуациях лучше использовать MLS-подходы. Соответственно, у нас будут три разных экземпляра Elasticsearch и Kibana, каждый из которых соответствует разным уровням очистки, и, таким образом, мы решаем проблему авторизации. Аутентификация для этих экземпляров может быть либо базовой HTTP-аутентификацией, либо на основе LDAP.
Шаг 1. Настройте несколько экземпляров Elasticsearch (ES) и предоставьте один общий URL-адрес конечным пользователям. В этом случае было установлено http: // localhost: 8081 .
Для этого эксперимента были созданы три экземпляра Elasticsearch, каждый из которых прослушивал свой порт на локальной машине.
1
2
3
|
ES Node 1 – http: //localhost:9201 ES Node 2 – http: //localhost:9202 ES Node 3 – http: //localhost:9203 |
Создайте три разных файла конфигурации Elasticsearch, по одному для каждого из этих экземпляров, и запустите их, используя следующую команду:
01
02
03
04
05
06
07
08
09
10
|
ES_HOME=/opt/elk/elasticsearch- 1.4 . 4 / nohup $ES_HOME/bin/elasticsearch \ -Des.config=$ES_HOME/config/elasticsearch_node1.yml >> /tmp/elasticsearch_node1.out \ 2 >& 1 & nohup $ES_HOME/bin/elasticsearch \ -Des.config=$ES_HOME/config/elasticsearch_node2.yml >> /tmp/elasticsearch_node2.out \ 2 >& 1 & nohup $ES_HOME/bin/elasticsearch \ -Des.config=$ES_HOME/config/elasticsearch_node3.yml >> /tmp/elasticsearch_node3.out \ 2 >& 1 & |
Пример файла конфигурации для Elasticsearch приведен в разделе ресурсов. Имя файла:
1
|
/opt/elk/elasticsearch- 1.4 . 4 /config/elasticsearch_node1.yml |
Шаг 2: Настройте несколько экземпляров Kibana, по одному для каждого уровня очистки и предоставьте один URL-адрес для конечных пользователей; в этом случае было установлено http: // localhost: 8082 .
Для этого эксперимента были созданы три экземпляра Kibana, каждый из которых слушал разные порты на локальной машине, соответствующие разным уровням разрешения.
1
2
3
|
Kibana Node 1 – http: //localhost:5701 - Top Secret – Connects to ES Node 1 Kibana Node 2 – http: //localhost:5702 - Secret – Connects to ES Node 2 Kibana Node 3 – http: //localhost:5703 - Public – Connects to ES Node 3 |
Запустите их, используя следующую команду:
1
2
3
|
nohup /opt/elk/kibana_nodes/kibana_node1/bin/kibana > /tmp/kibana_node1.out 2 >& 1 & nohup /opt/elk/kibana_nodes/kibana_node2/bin/kibana > /tmp/kibana_node2.out 2 >& 1 & nohup /opt/elk/kibana_nodes/kibana_node3/bin/kibana > /tmp/kibana_node3.out 2 >& 1 & |
Пример файла конфигурации для Kibana приведен в разделе ресурсов. Имя файла:
1
|
/opt/elk/kibana_nodes/kibana_node1/config/kibana.yml |
Шаг 3: Настройте прокси-сервер NGINX для прослушивания соединений с Elasticsearch (ES) или Kibana (NGINX будет прослушивать http: // localhost: 8081 для соединений с ES и http: // localhost: 8082 для соединений с Kibana). Пожалуйста, ознакомьтесь с файлом «Установка NGINX и LDAP Authentication.docx» в zip для пошаговых инструкций по его установке.
Аутентифицируйте пользователя по базе данных LDAP и проверьте, какой уровень авторизации он / она имеет на основании информации, прочитанной из базы данных (в этом случае использовался локальный файл, содержащий список пользователей и уровней авторизации), и перенаправьте пользователя на соответствующий сервер Elasticsearch / Kibana.
Сервер LDAP — работает в контейнере Docker ( https://github.com/osixia/docker-openldap )
База данных пользовательских ролей — файл представлен в разделе ресурсов (имя файла — «user_authorization_level.dat»)
Файл конфигурации NGINX — файл представлен в разделе ресурсов (имя файла — «nginx-ldap-auth-clusters.conf»)
Python Daemon для проверки на сервере LDAP (имя файла «nginx-ldap-auth-daemon.py»)
Форма входа в бэкэнд Python (имя файла «backend-sample-app.py»)
Оба вышеуказанных файла Python можно найти по адресу: https://github.com/nginxinc/nginx-ldap-auth
Шаг 4: Запустите сервер NGINX, как указано ниже:
Проверьте, запущены ли какие-либо процессы сервера NGINX, и уничтожьте их:
1
2
3
4
5
6
7
|
cd /usr/local/openresty/nginx/ sbin/nginx -s stop (Or) ps –ef | grep nginx kill - 9 <pid1> <pid2> …. <pidn> |
Запустите внутренний сервер:
1
2
|
cd /usr/local/openresty/nginx-ldap-auth python backend-sample-app.py |
Запустите демон аутентификации LDAP:
1
2
|
cd /usr/local/openresty/nginx-ldap-auth python nginx-ldap-auth-daemon.py |
Проверьте, запущены ли какие-либо процессы сервера NGINX, и уничтожьте их:
1
2
3
4
5
6
7
|
cd /usr/local/openresty/nginx/ sbin/nginx -s stop (Or) ps –ef | grep nginx kill - 9 <pid1> <pid2> …. <pidn> |
Запустите сервер NGINX с соответствующим файлом конфигурации:
1
2
|
cd /usr/local/openresty/nginx/ sbin/nginx -p $PWD -c conf/nginx-ldap-auth-clusters.conf |
Скриншоты:
Пользователь «admin» вошел в систему, и у него есть уровень «Совершенно секретно». Соответствующим этому сервером Kibana является http: // localhost: 5701, который подключен к серверу Elasticsearch http: // localhost: 9201, в котором есть только индекс «Шекспира».
Elasticsearch, показывающий, что на нем доступен только индекс «Шекспира»
Лог-файл, показывающий, что администратор «пользователя» имеет совершенно секретный уровень «разрешения»
Пользователь «Викаш» вошел в систему, и у него есть «Секретный» уровень допуска. Соответствующим этому сервером Kibana является http: // localhost: 5702, который подключен к серверу Elasticsearch http: // localhost: 9202, в котором есть индексы «logstash *».
Elasticsearch показывает, что на нем доступны только индексы «logstash *»
Файл журнала, показывающий, что «пользовательский» викаш имеет только секретный уровень «очистки»
Пользователь «swapnil» вошел в систему и имеет уровень «Public». Соответствующим этому сервером Kibana является http: // localhost: 5703, который подключен к серверу Elasticsearch http: // localhost: 9203, в котором есть только индекс «банк».
Elasticsearch показывает, что на нем доступен только «банковский» индекс
Файл журнала, показывающий, что swapnil пользователя имеет только публичный уровень очистки
Примечание. Все сопоставления и данные индекса были загружены с
https://www.elastic.co/guide/en/kibana/current/getting-started.html
КОДИРОВАНИЕ
Если бы вы внимательно заметили, вы бы поняли, что до сих пор мы использовали только «http». В производственных средах мы часто хотели бы использовать «https», поскольку это шифрует все данные и предотвращает кражу информации злоумышленниками. В приведенном ниже руководстве вы узнаете, как использовать протокол «https».
Шаг 1. Создайте самозаверяющий сертификат SSL.
01
02
03
04
05
06
07
08
09
10
11
12
13
|
cd /usr/local/openresty/nginx mkdir certs cd certs openssl genrsa 2048 > host.key openssl req - new -x509 -nodes -sha1 -days 3650 -key host.key > host.cert openssl x509 -noout -fingerprint -text < host.cert > host.info cat host.cert host.key > host.pem |
Шаг 2: Добавьте информацию, связанную с сертификатом, в файл конфигурации NGINX.
1
2
3
4
5
6
7
|
ssl on; ssl_certificate /usr/local/openresty/nginx/certs/host.cert; ssl_certificate_key /usr/local/openresty/nginx/certs/host.key; ssl_session_timeout 5m; ssl_protocols TLSv1. 2 TLSv1. 1 TLSv1; ssl_ciphers HIGH:!aNULL:!eNULL:!LOW:!MD5; ssl_prefer_server_ciphers on; |
Примечание. Полный файл конфигурации NGINX приведен ниже для справки.
NGINX прослушивает порт 8080 для соединений с ES и реализует базовую HTTP-аутентификацию
Конфигурационный файл NGINX
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
worker_processes 1 ; error_log /usr/local/openresty/nginx/logs/nginx_https.log debug; events { worker_connections 1024 ; } http { upstream elasticsearch { server 127.0 . 0.1 : 9200 ; keepalive 15 ; } server { listen 8080 ; keepalive_timeout 60s; ssl on; ssl_certificate /usr/local/openresty/nginx/certs/host.cert; ssl_certificate_key /usr/local/openresty/nginx/certs/host.key; ssl_session_timeout 1m; ssl_protocols TLSv1. 2 TLSv1. 1 TLSv1; ssl_ciphers HIGH:!aNULL:!eNULL:!LOW:!MD5; ssl_prefer_server_ciphers on; auth_basic "ElasticSearch" ; auth_basic_user_file /opt/elk/.espasswd; location / { proxy_pass http: //elasticsearch; proxy_http_version 1.1 ; proxy_set_header Connection "Keep-Alive" ; proxy_set_header Proxy-Connection "Keep-Alive" ; } } } |
Поскольку это самозаверяющий сертификат, вы увидите «красный» значок https, зачеркнутый. Если вы используете сертификат от доверенной третьей стороны, такой как Verisign, вы увидите, что он превращается в «зеленый» значок.
В этой записи блога вы узнали об одном из способов реализации аутентификации, авторизации и шифрования для Elasticsearch и Kibana. Если у вас есть какие-либо вопросы, пожалуйста, задавайте их в разделе комментариев ниже.
Ссылка: | Как обезопасить Elasticsearch и Kibana от нашего партнера JCG Чейза Хули в блоге Mapr . |