В этой статье мне хотелось бы поделиться способом настройки технологии единого входа (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.
REMOTE_USER=DOMAIN\user
.es-security-runas-user
.*@domain.name
.unmapped_groups_as_roles: true
. Это значит, что имя AD-группы будет именем роли в Elasticsearch (см. ниже про безопасность и производительность1)..kibana
. Значит, в AD нужно создать специальную группу, в которую будут включаться все те пользователи, которым нужно пользоваться Кибаной. Кроме того, в Elasticsearch нужно создать роль с таким же именем и с правами на изменение индекса .kibana
. Для примера, так будет выглядеть конфигурация пользователя отдела администрирования сетевого оборудования:ELK.Users
права на индекс .kibana*
:manage
, read
, index
, delete
ELK.Network.Admins
права на индексы net-*
:read
, view_index_metadata
REMOTE_USER
когда используется NTLM, так как встроенный IIS Rewrite модуль вызывается до аутентификации пользователя.Приступаем к настройке всех компонентов (мечта — написать инсталлятор...).
openssl pkcs12 -export -out domain.name.pfx -inkey domain.name.key -in domain.name.crt
Enable proxy [x]
Reverse proxy: localhost:5601
mmc
(с правами администратора) ? Add or Remove Snap-ins ? Certificates ? Add ? Computer account ? Local computer ? Certificates (Local computer) ? Trusted Root Certification Authorities ? Certificate ? импортируем "CA.crt"По умолчанию модуль устанавливается в C:\Program Files
.
Добавляем в конфигурационный файл C:\Program Files\Helicon\ISAPI_Rewrite3\httpd.conf
следующее:
RewriteEngine on
RewriteCond %{REMOTE_USER} (.*)\\(.*)
RewriteHeader es-security-runas-user: .* (%2)(@company.com)
RewriteHeader Authorization: .* (Basic\ aWlzOnNlY3JldHBhc3N3b3Jk)
RewriteRule ^/logout / [R,L]
Как это работает:
DOMAIN\user
конвертируется модулем в формат userPrincipalName
(user@company.com
) и отправляется Кибане новым HTTP заголовком es-security-runas-user
aWlzOnNlY3JldHBhc3N3b3Jk
это закодированные base64 логин и пароль технического пользователя: iis:secretpassword
(его мы создадим в Elasticsearch чуть позже)./logout
, мы просто перенаправим его на стартовую страницу Кибаны, где он опять автоматически авторизуетсяДля SSO добавляем следующие параметры в kibana.yml
:
elasticsearch.requestHeadersWhitelist: [ es-security-runas-user, authorization ]
xpack.monitoring.elasticsearch.requestHeadersWhitelist: [ es-security-runas-user, authorization ]
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 Error\n 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.х).
{ statusCode: 500, error: Internal Server Error, message: An internal server error occurred }
В принципе, можно в том же Helicon Rewrite написать редирект при появлении этой ошибки, на кастомную страничку, которую можно поместить в:
<kibana-home>\optimize\bundles
Страничка будет доступна по адресу:
https://localhost/bundles/custom/error.htm
Надеюсь, что теперь в Вашей организации уровень "юзер-экспириенса" и прочего "сатисфэкшена" будет ещё больше!
[1] Следующие соображения безопасности и производительности должны быть приняты во внимание при использование unmapped_groups_as_roles: true
superuser
и добавлении в неё своей учётной записи, администратор становится супер-пользователем кластера, т.к. роль superuser
является встроенной и её нельзя отключить или удалить. Тоже самое будет справедливым для других встроенных ролей: logstash_admin
, machine_learning_admin
и т.д. Никаких "воркэраундов" предложить не могу, только аудит AD.ELK.*
.cache.ttl
.Если Вы всё же решили не использовать этот автоматический маппинг через AD-группы по описанным выше причинам, то отображать группы в роли придётся или через файлы или через API. ↩
[2] В продукции создавать такую супер-пользовательскую роль не рекомендуется. Администрировать лучше по старинке — супер-юзером elastic
и через curl
. ↩
К сожалению, не доступен сервер mySQL