В этой статье мне хотелось бы поделиться способом настройки технологии единого входа (SSO) в Elastic Stack, использующим X-Pack для аутентификации пользователей и разграничения доступа к данным.
Надо сказать, что активные попытки настроить SSO в Кибане с Active Directory начались у меня после прочтения статьи Integrating third party Auth with Kibana. Как всегда в таких блогах был приведён простой и рабочий пример, который подходит для "домашнего использования", но мало применимый на предприятиях со сложной инфраструктурой. И вот только после выхода Elastic Stack v.5.6.2, а если более конкретно — патча в X-Pack 5.6.2, который наконец-то сделал возможным использвание “user impersonation” c Active Directory, единый вход (SSO) заработал в полной мере.
“Олицетворение пользователя” (user impersonation) — это ключевой компонент в этой системе, с помощью которого одной учётной записи (например технический пользователь) разрешается посылать запросы от имени других, уже аутентифицированных пользователей. В Elastic Stack X-Pack эта функция называется run_as.
Справедливости ради надо заметить, что SSO можно было настроить и до этого патча — если использовать LDAP. Но так как LDAP realm в Elasticsearch не поддерживает вложенные группы (nested groups), то рассматривать это решение было не серьёзно.
Архитектура
Архитерктура предлагаемого решения будет выглядеть следующим образом:
Картинка позаимствована в уже упомянутом блоге, изменены только названия у нескольких компонентов. Надеюсь, что Эластик не будет возражать (если узнает), а если будет, то придётся нарисовать свои квадратики в PPT.
Описание работы
- Пользователи посылают запрос на веб-сервер (IIS), который аутентифицирует их через механизм Windows Authenticated (все остальные методы аутентификации отключены в конфигурации этого веб-сайта).
- Если аутентификация прошла успешно, то IIS устанавливает переменную окружения
REMOTE_USER=DOMAINuser
. - Эта переменная будет использоваться в дополнительном модуле Helicon rewrite для установки имперсонифицированного HTTP-заголовка (impersonation header)
es-security-runas-user
. - Модуль Helicon rewrite устанавливает также и HTTP-заголовок аутентификации (Basic) для специального технического внутреннего пользователя Elasticsearch.
- Специальная роль в Elasticsearch используется для разрешения запуска поисковых запросов от имени других пользователей. Так как имперсонификация должна быть разрешена только для пользователей домена, то эта роль будет выглядеть примерно так:
*@domain.name
. - Настраиваем AD realm для X-Pack'a
- Так как доступ пользователей к индексам будет регулироваться только через AD-группы, то AD-realm должен использовать параметер
unmapped_groups_as_roles: true
. Это значит, что имя AD-группы будет именем роли в Elasticsearch (см. ниже про безопасность и производительность1). - Все пользователи нашей системы (Кибаны), вне зависимости от того, к каким индексам в Elasticsearch им предоставлен доступ, должны иметь права на чтение и запись в индекс
.kibana
. Значит, в AD нужно создать специальную группу, в которую будут включаться все те пользователи, которым нужно пользоваться Кибаной. Кроме того, в Elasticsearch нужно создать роль с таким же именем и с правами на изменение индекса.kibana
. Для примера, так будет выглядеть конфигурация пользователя отдела администрирования сетевого оборудования:- Пользователь Кибаны: AD-группа = ES роль =
ELK.Users
права на индекс.kibana*
:manage
,read
,index
,delete
- Доступ к сетевым логам: AD-группа = ES роль =
ELK.Network.Admins
права на индексыnet-*
:read
,view_index_metadata
- Пользователь Кибаны: AD-группа = ES роль =
Установка
- Настраиваем TLS на Кибане и Elasticsearch сервере: инструкция. Этот пункт опциональный, но желательный — несолидно ведь предлагать систему аутентификации без шифрования траффика.
- Устанавливаем IIS (Microsoft Internet Information Services) для аутентификации пользователей через NTLM. Так как этот веб-сервер будет использоваться в качестве прокси и никакой другой работы выполнять не будет, можно IIS установить на одном сервере с Кибаной.
- "Улучшаем" IIS:
- Application Request Routing (ARR) — расширение, которое позволяет IIS работать в качестве балансера нагрузки. В нашем случае он будет использваться как обратный прокси сервер (reverse proxy).
- Helicon ISAPI_Rewrite 3 engine — сторонный модуль, эмулирующий работу движка Apache rewrite. Он нужен, потому что IIS (на данный момент) не может установить переменную
REMOTE_USER
когда используется NTLM, так как встроенный IIS Rewrite модуль вызывается до аутентификации пользователя.
Конфигурация
Приступаем к настройке всех компонентов (мечта — написать инсталлятор...).
IIS
- Настройка SSL
В сети полно инструкций для настройки SSL/TLS в IIS, например IIS SSL how-to. Но я всё равно перечислю некоторые шаги. Предположим, что у нас уже есть PEM сертификат, конвертируем его в PKCS#12 формат для IIS:
openssl pkcs12 -export -out domain.name.pfx -inkey domain.name.key -in domain.name.crt
- Импортируем этот сертификат в IIS:
- IIS Manager ⇒ Top level navigation tree ⇒ Server certificates ⇒ Import …
- Выбираем этот сертификат в Binding'e для HTTPS (port 443) в нашем сайте:
- IIS Manager ⇒ Top level navigation tree ⇒ Sites ⇒ Default Web Site ⇒ Bindings…
- Настраиваем обратный прокси для коммуникации IIS ⇔ Kibana (предполагается, что Кибана работает локально на том же сервере и использует свой стандартный порт — 5601)
- IIS Manager ⇒ Top level navigation tree ⇒ Application Request Routing Cache ⇒ Server Proxy Settings … ⇒
- IIS Manager ⇒ Top level navigation tree ⇒ Sites ⇒ Default Web Site ⇒ Bindings…
Enable proxy [x]
Reverse proxy: localhost:5601
- Центр сертификации (Certificate authority) сертификата Kibana
Если случилось так, что сертификат Кибаны подписан "незнакомым" СА (не из PKI организации), то этот СА необходимо добавить в “Trusted Root Certification Authorities” на сервере с IIS:- Вызываем
mmc
(с правами администратора) ⇒ Add or Remove Snap-ins ⇒ Certificates ⇒ Add ⇒ Computer account ⇒ Local computer ⇒ Certificates (Local computer) ⇒ Trusted Root Certification Authorities ⇒ Certificate ⇒ импортируем "CA.crt"
- Вызываем
Helicon Rewrite engine
По умолчанию модуль устанавливается в C:Program Files
.
Добавляем в конфигурационный файл C:Program FilesHeliconISAPI_Rewrite3httpd.conf
следующее:
RewriteEngine on
RewriteCond %{REMOTE_USER} (.*)\(.*)
RewriteHeader es-security-runas-user: .* (%2)(@company.com)
RewriteHeader Authorization: .* (Basic aWlzOnNlY3JldHBhc3N3b3Jk)
RewriteRule ^/logout / [R,L]
Как это работает:
- после аутентификации пользователя его логин
DOMAINuser
конвертируется модулем в форматuserPrincipalName
(user@company.com
) и отправляется Кибане новым HTTP заголовкомes-security-runas-user
- добавляем еще один HTTP заголовок для Basic авторизации, где значение
aWlzOnNlY3JldHBhc3N3b3Jk
это закодированные base64 логин и пароль технического пользователя:iis:secretpassword
(его мы создадим в Elasticsearch чуть позже). - ну и если пользователь кликнет на
/logout
, мы просто перенаправим его на стартовую страницу Кибаны, где он опять автоматически авторизуется
Kibana
Для SSO добавляем следующие параметры в kibana.yml
:
elasticsearch.requestHeadersWhitelist: [ es-security-runas-user, authorization ]
xpack.monitoring.elasticsearch.requestHeadersWhitelist: [ es-security-runas-user, authorization ]
Elasticsearch
X-Pack уже установлен, конфигурируем AD в elasticsearch.yml
:
xpack:
security:
authc:
realms:
native_realm:
type: native
order: 0
company_ad_realm:
enabled: true
type: active_directory
order: 1
domain_name: company.com
user_search:
base_dn: "DC=company,DC=com"
group_search:
base_dn: "DC=company,DC=com"
url: ldaps://server.company.com:636
ssl.verification_mode: none
bind_dn: "CN=user,OU=People,DC=company,DC=com"
bind_password: "XXXXXXXXXX"
unmapped_groups_as_roles: true
cache.ttl: 300s
Пользователь, указанный в bind_dn
, должен обладать правами на подключение и поиск в AD.
Проверка сертификата AD оключена (ssl.verification_mode: none
), потому что центр сертификации (СА) AD не указан (параметр: ssl.certificate_authorities
).
Создаем в Elasticsearch технического пользователя (iis
) и роль (тоже iis
) для имперсонизации ("олицетворение пользователя" — звучит ещё ужаснее):
POST _xpack/security/role/iis
{
"run_as": [
"*@company.com"
]
}
POST _xpack/security/user/iis
{
"password": "secretpassword",
"roles": [
"iis"
],
"full_name": "Service Account for IIS reverse proxy"
}
Теперь создаем роль для всех пользователей Кибаны. Напомню — имя роли должно быть именем группы в AD, члены которой будут иметь доступ к Кибане (пусть эта группа называется "ELK.Users"):
POST _xpack/security/role/ELK.Users
{
"indices": [
{
"names": [
".kibana*"
],
"privileges": ["read", "manage", "index", "delete"]
}
]
}
Кибана хранит все настройки в одном индексе (.kibana
или .kibana-6
), поэтому все пользователи Кибаны должны иметь права на чтение и запись в этот индекс.
Теперь, для примера, создадим роль, члены которой будут иметь доступ к индексам net-*
, в которых хранятся данные с сетевых устройств:
POST _xpack/security/role/ELK.Network.Admins
{
"indices": [
{
"names": [
"net-*"
],
"privileges": ["read", "view_index_metadata"]
}
]
}
Ещё один пример — "кастомная" супер-пользовательская роль для администраторов Elasticsearch2:
POST _xpack/security/role/ELK.Admins
{
"cluster": [
"all"
],
"indices": [
{
"names": [
"*"
],
"privileges": [
"all"
]
}
]
}
Таким образом, члены AD-группы "ELK.Admins" получают полный доступ к Elasticsearch кластеру.
Результат
Включаем и удивляемся! Про ввод логина можно забыть.
При открытии корневой страницы нашего IIS-proxy сайта, пользователь был успешно аутентифицирован.
Замечание: если этот пользователь имеет доступ только к данным индексов net-*
, то он всё равно будет видеть все сконфигурированные индексы в Кибане — обратите внимание на выпадающий список. Но при выборе индексов, к которым он не имеет доступа, пользователь будет видеть No results found. Но эта проблема к SSO не имеет отношения.
"Что-то пошло не так"
Тестирование и устранение неполадок.
Случай 1: Пользователя (или его группу) забыли добавить в AD-группу "пользователей Кибаны" (ELK.Users
) или он вообще не должен иметь доступа к Кибане:
Config: Error 403 Forbidden: action [indices:data/write/update] is unauthorized for user [iis] run as [user@company.com]: [security_exception] action [indices:data/write/update] is unauthorized for user [iis] run as ...
Пользователь был успешно аутентифицирован IIS (NTLM, Kerberos и т.д.) и посредством технического пользователя iis
аутентифицировался в Кибане. Но т.к. реальный аккаунт user@company.com
не входит в AD-группу "любителей Кибаны", то и в Elasticsearch у него нет роли на запись/чтение в индекс .kibana
.
Я пока не знаю, как сделать сообщение или страничку "доступ запрещен" более "дружелюбным".
Случай 2: IIS использует SSL в конфигурации прокси-модуля (опция "Enable SSL offloading" выключена, как и задумано), a в Кибане забыли настроить HTTPS. Тогда мы можем наблюдать следующее в kibana.log
:
{"type":"log","@timestamp":"2017-10-03T15:11:32Z","tags":["connection","client","error"],"pid":10416,"level":"error","message":"Parse Error","error":{"message":"Parse Error","name":"Error","stack":"Error: Parse Errorn at Error (native)","code":"HPE_INVALID_METHOD"}}
Случай 3: Центр сертификации, подписавший сертификат Кибаны, неизвестен IIS
Открываем стартовую страничку IIS-Kibana:
HTTP Error 502.3 - Bad Gateway
A security error occurred
и соответствующая ошибка в логе Кибаны:
"code":"ECONNRESET"
"message":"socket hang up"
Случай 4: Аутентификация Windows не включена для нашего веб-сайта
Tогда пользователи будут аутентифицированы в Кибане как iis
юзер: "Service Account for IIS reverse proxy"
Тест 1: Всё в порядке с AD/LDAP? И как там дела обстоят с членством?
Используем ldapsearch
или adfind
— всячески рекомендую, скачивать здесь
ldapsearch -h server.company.com -b "DC=company,DC=com" -D "CN=user,OU=People,DC=company,DC=com" -w "XXXXXXX" samaccountname=user
adfind -f "userprincipalname=user@company.com"
Тест 2: Тестируем имперcонизацию
curl -k -v -u iis:secretpassword -H "es-security-runas-user: user@company.com" https://elastic-server:9200/.kibana/_search
Если этот тест пройден (HTTP/1.1 200 OK
), то Elasticsearch настроен правильно, и может проверить права пользователя в AD.
Ну а если получаем что-то вроде:
{"error":{"root_cause":[{"type":"security_exception","reason":"action [indices:data/read/search] is unauthorized for user [iis] run as [user@company.com]"}],"type":"security_exception","reason":"action [indices:data/read/search] is unauthorized for user [iis] run as [user@company.com]"},"status":403}
то самое время включать дебаг и читать логи Elasticsearch'a:
PUT /_cluster/settings
{
"transient": {
"logger.org.elasticsearch.xpack.security.authc": "trace"
}
}
Тест 3: Изменяем членство пользователя в AD и, чтобы Elasticsearch не ожидал инвалидации кэша, очищаем последний вручную
curl -k -u 'elastic:changeme' -X POST https://elastic-server:9200/_xpack/security/realm/company_ad_realm/_clear_cache
Примечание: elastic
— это встроенный пользователь с паролем по-умолчанию (в версии 5.х) или с измененным на такой же (версия 6.х).
To-Dos
- Создать "дружелюбную" страницу при возникновении “Internal Server Error”
Если Elasticsearch не может проверить пользователя, по какой-либо причине (например, нет соединения с AD), то Кибана покажет такую JSON страничку:
{ statusCode: 500, error: Internal Server Error, message: An internal server error occurred }
В принципе, можно в том же Helicon Rewrite написать редирект при появлении этой ошибки, на кастомную страничку, которую можно поместить в:
<kibana-home>optimizebundles
Страничка будет доступна по адресу:
https://localhost/bundles/custom/error.htm
Спасибо за внимание!
Надеюсь, что теперь в Вашей организации уровень "юзер-экспириенса" и прочего "сатисфэкшена" будет ещё больше!
[1] Следующие соображения безопасности и производительности должны быть приняты во внимание при использование unmapped_groups_as_roles: true
- Администратор AD теоретически получает полный доступ к ES кластеру: при создании в AD группы с именем
superuser
и добавлении в неё своей учётной записи, администратор становится супер-пользователем кластера, т.к. рольsuperuser
является встроенной и её нельзя отключить или удалить. Тоже самое будет справедливым для других встроенных ролей:logstash_admin
,machine_learning_admin
и т.д. Никаких "воркэраундов" предложить не могу, только аудит AD. - Необходимо тщательно планировать и соблюдать соглашение о наименовании групп в AD (naming convention), чтобы избежать несанкционированного доступа к данным. Используйте префиксы (суфиксы) в именах групп для доступа к ES кластеру, например
ELK.*
. - Elasticsearch будет проверять каждую группу пользователя, на соответвии её роли в кластере. При большом количестве групп, в которые включён пользователь, эта проверка будет влиять на производительность. В крупных организациях, где пользователи имеют сотни, или даже тысячи групп, это может быть проблемой. Но, предупреждён — значит вооружён. К тому же, Elasticsearch кэширует группы и не обращается к AD при каждом поисковом запросе, см. параметр
cache.ttl
.
Если Вы всё же решили не использовать этот автоматический маппинг через AD-группы по описанным выше причинам, то отображать группы в роли придётся или через файлы или через API. ↩
[2] В продукции создавать такую супер-пользовательскую роль не рекомендуется. Администрировать лучше по старинке — супер-юзером elastic
и через curl
. ↩
Автор: jetnet