В этой части нашего цикла заметок об Icinga будет рассмотрен пример того, как можно организовать доменную аутентификацию пользователей Active Directory (AD) с поддержкой Kerberos и Single sign-on (SSO) при подключении к веб-консоли Icinga Web 2.
Если мы заглянем в опорный документ Icinga Web 2 Authentication, то узнаем, что веб-консоль Icinga Web 2 способна работать с аутентификаций, основанной на каталоге Active Directory, других реализациях LDAP-каталогов, базах данных MySQL или PostgreSQL, а также делегировать процесс аутентификации непосредственно веб-серверу. Так, как в рассматриваемом нами примере будут использоваться такие вещи, как аутентификация с помощью Kerberos и дополнительная авторизация с помощью PAM, выбран вариант с делегированием процесса аутентификации веб-серверу. При этом процедуры внутренней проверки прав доступа к объектам веб-консоли Icinga Web 2 будут выполняться через специально созданное подключение к AD, как к LDAP-каталогу.
Подготовка инфраструктуры
Предполагаем, что наш сервер с Icinga Web 2 уже присоединён к домену Active Directory с помощью SSSD/realmd и на нём настроен Kerberos-клиент для взаимодействия с доменом: Подключение Debian GNU/Linux 8.6 к домену Active Directory с помощью SSSD и realmd.
Создадим в домене Active Directory две сервисные учётные записи доменного пользователя. Первую - для подключения и поиска в LDAP-каталоге (например DOM\s-Icinga-Apache-LDAP), вторую - для Kerberos-аутентификации пользователей, вызываемую веб-сервером Apache (например DOM\s-Icinga-Apache-Krb).
Для учётной записи DOM\s-Icinga-Apache-Krb необходимо зарегистрировать в домене запись servicePrincipalName (SPN) веб-сервера и сгенерировать keytab-файл, содержащий данную SPN-запись. Повторяться не буду, так как эта процедура пошагово рассмотрена в одной из прошлых заметок (см. пункты «Создание в домене AD сервисной учётной записи» и «Создание keytab-файла для сервисной учётной записи»). Предполагая, что необходимый keytab-файл у нас уже есть, размещаем его в доступном для службы веб-сервера месте и ограничиваем к нему доступ:
# chown www-data:root /etc/apache2/s-Icinga-Apache-Krb.keytab
# chmod 400 /etc/apache2/s-Icinga-Apache-Krb.keytab
Используемая здесь учётная запись www-data - это пользователь по умолчанию, от имени которого запускается служба apache2 в Debian.
***
Создадим в домене Active Directory группы безопасности, через членство в которых мы будем управлять доступом к Icinga Web 2.
Для начала создадим низкоуровневые группы доступа для администраторов (Icinga-Administrators@holding.com) и для пользователей (Icinga-Operators@holding.com). Эти группы будут определять совокупность доменных пользователей имеющих право доступа к веб-консоли Icinga, как таковой.
При необходимости создадим дополнительные группы более высокого уровня, которые будут иметь доступ только к информации о состоянии определённых хостов. Например, создадим отдельную группу для специалистов Телеком-блока Icinga-Telecom@holding.com и включим эту группу в группу Icinga-Operators@holding.com.
Создаём политику PAM
По аналогии с ранее описанным принципом, создадим в каталоге /etc/pam.d/ файл описания отдельной политики PAM, которая для процедур аутентификации и авторизации будет вызывать библиотеку SSSD:
# nano /etc/pam.d/apache2-icingaweb2
Наполним файл содержимым:
auth required pam_sss.so
account required pam_listfile.so onerr=fail item=group sense=allow file=/etc/security/icingaweb2
account required pam_sss.so
Первая строка определяет вызов библиотеки SSSD для аутентификации, вторая и третья строки отвечают за авторизацию. Вторая строка добавляет проверку членства в группе для аутентифицированного пользователя. При этом группы для проверки считываются из файла /etc/security/icingaweb2, который нам нужно создать дополнительно. В этом файле будут перечисляться доменные группы безопасности, которым можно разрешить доступ к веб-консоли Icinga:
Icinga-Administrators@holding.com
Icinga-Operators@holding.com
Таким образом мы организовали низкоуровневое ограничение доступа к веб-консоли Icinga, чтобы к ней не могли беспрепятственно подключаться любые аутентифицированные пользователи домена. Более высокоуровневое разграничение доступа к самим объектам мониторинга в веб-консоли Icinga мы рассмотрим далее на примере группы Icinga-Telecom@holding.com.
Добавляем LDAP-ресурс для авторизации в Icinga Web 2
Подключимся к веб-консоли Icinga Web 2 и добавим новый ресурс, который будет использоваться в качестве подключаемого источника данных. В меню навигации перейдём в Configuration > Application, переключимся на закладку Resources и нажмём Create a New Resource.
В открывшейся справа форме создания нового ресурса заполним все необходимые поля:
- В качестве типа ресурса выберем LDAP;
- Присвоим простое имя ресурсу, например "icingaweb_ldap";
- В качестве хоста укажем имя контроллера домена AD;
- Тип шифрования и порт - 389 (для незащищённого соединения по протоколу LDAP или защищённого по протоколу StartTLS) либо 636 (для защищённого соединения по протоколу LDAPS);
- Root DN – коневой контейнер или OU в AD, в котором будет производиться поиск объектов (группы и пользователи);
- Bind DN/Password – Имя пользователя (в формате distinguishedName) и пароль, от созданной нами ранее в домене служебной учётной записи DOM\s-Icinga-Apache-LDAP
После того, ка все атрибуты создаваемого ресурса заданы, произведём проверку подключения к LDAP-каталогу с помощью кнопки Validate Configuration.
И если в настройках мы выбрали шифрование LDAP-соединений с помощью StartTLS или LDAPS, вероятней всего получим сообщение об ошибке, говорящее о проблемах установления соединения
Это вполне резонно, так как в конфигурации по умолчанию ldap-клиент на нашем сервере Icinga настроен таким образом, что перед установкой защищённого соединения пытается провести проверку подлинности цифрового сертификата, который предоставляет ему контроллер домена AD на начальном этапе соединения. И здесь нам придётся немного отвлечься от Icinga, чтобы решить данную проблему.
***
Есть 2 варианта решения этой проблемы - неправильный и правильный. Начнём с неправильного, так как он наиболее прост. Решение заключается в отключении механизма проверки сертификатов для SSL/TLS и оно коснётся всех сервисов в системе, которые пользуются услугами ldap-клиента (OpenLDAP), что само по себе не очень правильно и хорошо.
Открываем файл /etc/ldap/ldap.conf, комментируем параметр TLS_CACERT и добавляем строчку TLS_REQCERT never:
...
#TLS_CACERT /etc/ssl/certs/ca-certificates.crt
TLS_REQCERT never
Правильный же вариант заключается в том, чтобы добавить на наш сервер Icinga доверенные корневые сертификаты корпоративных доменных Центров сертификации, которыми были выданы сертификаты, используемые нашими контроллерами домена AD. В результате этого ldap-клиент сможет использовать добавленные корневые сертификаты для проверки сертификатов, предоставляемых контроллерами домена Active Directory, когда мы будем к ним подключаться с использованием SSL/TLS в процессе аутентификации и авторизации доменных пользователей на веб-консоли Icinga. Описание этой несложной процедуры можно найти на отдельной Вики-странице: Добавление в Linux корневых сертификатов X.509 локального корпоративного Центра сертификации. Так, как в нашем случае сервер Icinga развёрнут на базе Debian GNU/Linux, нам потребуется создать отдельный файл-бандл, который будет содержать в себе все доверенные сертификаты доменных ЦС и указать этот файл в конфигурации клиента OpenLDAP. Имея на руках все корневые сертификаты доменных ЦС, объединяем их в один файл.
# mkdir /etc/ssl/certs-corp-ca
# cat ./AD-RootCA.pem ./AD-SubCA.pem > /etc/ssl/certs-corp-ca/AD-Chain.pem
Правим конфигурацию клиента OpenLDAP (/etc/ldap/ldap.conf), указав в параметре TLS_CACERT путь к файлу, в который мы только что собрали доверенные корневые сертификаты доменных ЦС. При этом прочие параметры TLS_CA* лучше закомментировать:
...
#TLS_CACERT /etc/ssl/certs/ca-certificates.crt
#TLS_CACERTDIR /etc/ssl/certs
TLS_CACERT /etc/ssl/certs-corp-ca/AD-Chain.pem
***
После сделанных изменений вернёмся в веб-интерфейс Icinga Web 2 и снова проведём валидацию создаваемого нами LDAP-ресурса:
Как видим, на этот раз соединение с использованием защищённого протокола прошло успешно.
После сохранения, заданная нами через веб-интерфейс конфигурация нового ресурса будет сохранена в файле /etc/icingaweb2/resources.ini
[icingaweb_db]
...
[icinga_ido]
...
[director_db]
...
[icingaweb_ldap]
type = "ldap"
hostname = "dc01.holding.com"
port = "389"
encryption = "starttls"
root_dn = "OU=KOM,DC=holding,DC=com"
bind_dn = "CN=s-Icinga-Apache-LDAP,OU=Security Users,OU=KOM,DC=holding,DC=com"
bind_pw = "StrOnGPass0rwD"
Далее созданный LDAP-ресурс мы будем использовать при создании User Group Backend для авторизации в Icinga Web 2.
Добавляем User Backend для аутентификации в Icinga Web 2
Так как мы хотим использовать преимущества Kerberos и SSO для автоматической аутентификации доменных пользователей при подключении к веб-консоли Icinga Web 2, нам потребуется создать User Backend со специальным типом External, то есть передать управление процедурой аутентификации пользователей непосредственно веб-серверу Apache. Однако если в веб-консоли мы заглянем туда, где создаются объекты типа User Backend (Configuration > Application, закладка Authentication - Create a New User Backend), то увидим, что в текущей версии Icinga Web 2 среди возможных для выбора типов Backend Type нет типа External.
Не знаю почему так, но это вполне разрешимый вопрос, так как в создание внешнего аутентификатора описано в документе 05-Authentication.md
Перейдём на консоль нашего сервера Icinga и добавим руками новую секцию [kerberos] перед секцией [icingaweb2] в конфигурационном файле /etc/icingaweb2/authentication.ini
[kerberos]
backend = "external"
strip_username_regexp = "/@.*$/"
[icingaweb2]
backend = "db"
resource = "icingaweb_db"
В параметре backend укажем ключевое слово "external", а в дополнительном параметре strip_username_regexp укажем регулярное выражение, с помощью которого из имени аутентифицированного пользователя будет отсекаться доменный суффикс.
Теперь вернёмся в веб-консоль Icinga Web 2, обновим страницу, и проверим, что в списке User Backend отображается добавленный нами через конфигурационный файл внешний аутентификатор. Нажмём кнопку Validate Configuration и убедимся в том, что веб-консоль не возвращает ошибок:
Аутентификация в Icinga Web 2 настроена, переходим к настройке авторизации.
Добавляем User Group Backend для авторизации в Icinga Web 2
Теперь создадим в Icinga Web 2 объект типа User Group Backend, который будет использоваться для механизма авторизации (проверки членства аутентифицированного пользователя в группах AD). Перейдём в Configuration > Application, выберем закладка Authentication и нажмём Create a New User Group Backend.
В открывшейся справа форме создания User Group Backend выберем тип ActiveDirectory, укажем понятное нам имя, например "icingaweb2_AD_group". В поле LDAP Connection из выпадающего списка выберем созданный нами ранее LDAP-ресурс. Поле User Backend оставляем без выбора, так как по условиям нашей задачи используется внешний аутентификатор. Отметим опцию Nested Group Search, чтобы при поиске членства в доменных группах учитывались вложенные группы. Остальные параметры можно оставить предложенные по умолчанию, если конечно нам не требуется дополнительная LDAP-фильтрация, которую можно здесь настроить.
После сохранения созданного User Group Backend, его конфигурация попадёт в файл /etc/icingaweb2/groups.ini, который примет примерно следующий вид:
[icingaweb2]
backend = "db"
resource = "icingaweb_db"
[icingaweb2_AD_group]
resource = "icingaweb_ldap"
user_backend = "none"
group_class = "group"
group_name_attribute = "sAMAccountName"
group_member_attribute = "member"
backend = "msldap"
nested_group_search = "1"
Параметры авторизации настроены, переходим к проверке.
Проверяем возможность поиска доменных групп
На данном этапе фактическое соединение Icinga Web 2 c AD настроено и теперь мы можем проверить, как работает поиск доменных групп безопасности. Перейдём в веб-консоли в Configuration > Authentication и переключимся на закладку User Groups. Здесь из выпадающего списка выберем ранее созданный User Group Backend и убедимся в том, что поиск групп работает и группа отображает свой состав
Если всё в порядке, то можем приступать к созданию Ролей Icinga Web 2, привязанных к доменным группам безопасности.
Создаём роли с привязкой к доменным группам
Для разграничения прав доступа к объектам веб-консоли Icinga Web 2 используется ролевая модель. Давайте попробуем создать пару Ролей. Для этого перейдём в Configuration > Authentication, и на закладке Roles нажмём Create a New Role.
В открывшейся справа форме добавления Роли, укажем понятное нам имя роли. Предположим, это будет роль Администраторов Icinga с неограниченными правами доступа. В поле Groups укажем имя доменной группы безопасности, которая объединяет администраторов Icinga. В перечне набора прав выберем первую позицию – Allow everything, которая определяет неограниченный доступ.
Теперь по аналогии создадим вторую роль, но уже с ограниченным доступом к объектам в icinga Web 2. Предположим, что у нас в Icinga есть Группа Хостов с именем "KOM-Telecom" и эта группа привязана только к некоторым хостам (клиентам Icinga), доступ к которым в веб-консоли мы и хотим разрешить для специалистов Телеком-блока, которые входят в доменную группу безопасности Icinga-Telecom@holding.com.
Создадим соответствующую Роль с привязкой к доменной группе безопасности. В наборе прав доступа Permissions Set на этот раз снимем указатель с верхней позиции, разрешающей всё, и отметим только те вещи, к которым нужно разрешить доступ. А в дополнительных полях фильтрации добавим фильтр по имени Группы Хостов:
По аналогии мы можем создать столько Ролей с привязкой к доменным группам безопасности, сколько потребуется. Создаваемые нами роли будут попадать на сервере Icinga Web 2 в конфигурационный файл /etc/icingaweb2/roles.ini:
[Administrators]
users = "icingaweblocaladmin"
permissions = "*"
groups = "Administrators"
[Administrators_AD]
groups = "Icinga-Administrators"
permissions = "*"
[Telecom]
groups = "Icinga-Telecom"
permissions = "module/director, director/inspect, module/monitoring, monitoring/command/schedule-check"
monitoring/filter/objects = "hostgroup_name=KOM-Telecom"
Можем считать, что с настройкой авторизации закончили, теперь перейдём к настройке внешней аутентификации пользователей средствами веб-сервера Apache.
Настройка Apache на Kerberos-аутентификацию и PAM авторизацию
По началу для аутентификации в Apache я попробовал вместо модуля auth-kerb использовать модуль auth-gssapi, по аналогии с тем, как это было описано ранее, однако такой вариант в моём окружении не заработал, возможно в силу того, что в репозиториях Debian Jessie модуль auth-gssapi довольно старой версии (1.0.3-2) и эта версия имеет какие-то проблемы. Поэтому в данном примере я буду использовать уже проверенный модуль auth-kerb.
Итак, устанавливаем модули, необходимые веб-серверу Apache в Debian для поддержки Kerberos-аутентификации с дополнительной авторизацией через PAM:
# apt-get install libapache2-mod-auth-kerb libapache2-mod-authnz-pam
Устанавливаемые модули будут автоматически включены в конфигурацию Apache на заключительном этапе установки. Можно проверить, присутствуют ли среди активированных модулей Apache нужные нам модули:
# apache2ctl -M | grep -E "kerb|pam"
auth_kerb_module (shared)
authnz_pam_module (shared)
Отредактируем конфигурационный файл Apache, определяющий конфигурацию веб-узла Icinga Web 2 ( по умолчанию это файл /etc/apache2/conf-available/icingaweb2.conf ), дополнив в нём секцию, где описан доступ к каталогу /usr/share/icingaweb2/public:
...
<Directory "/usr/share/icingaweb2/public">
AuthType Kerberos
AuthName "Kerberos Login"
Krb5Keytab /etc/apache2/s-Icinga-Apache-Krb.keytab
KrbAuthRealms HOLDING.COM
KrbMethodK5Passwd on
Require pam-account apache2-icingaweb2
...
</Directory>
...
Как видно, здесь используется аутентификация Kerberos c ранее приготовленным keytab-файлом и вызовом ранее созданной политики PAM "apache2-icingaweb2" для авторизации пользователей.
После внесённых изменений перезапустим службы Icinga и Apache:
# systemctl restart icinga2
# systemctl restart apache2
Теперь попытаемся с клиентского компьютера получить доступ к веб-консоли Icinga Web 2 и процедура аутентификации и авторизации должна пройти для пользователя прозрачно без каких либо запросов на ввод учётных данных.
Опционально: Страница ошибки 401 для Apache
При желании можно дополнительно оформить свою веб-страницу, которая будет показываться пользователям, не имеющим доступа к веб-консоли Icinga Web 2. Для этого в корневой каталог Apache по умолчанию ( /var/www/html/ ) поместим подготовленную HTML-страничку, например IcingaUnauthorized.html:
Однако практические тесты показали, что адекватно такую страницу пользователям отображает только браузер Mozilla Firefox. Internet Explorer, в свойственной ему манере, показывает собственную страницу ошибки (не говорю уже про чудоковатое требование к тому, что размер кастомной страницы ошибок должен превышать определённый размер в байтах). А Google Chrome вообще выплёвывает из себя что-то типа ERR_INVALID_RESPONSE. Поэтому, делать страницу ошибки или нет - остаётся делом вкуса.
Защита соединений с веб-сервером с помощью SSL-сертификата
Не смотря на то, что для аутентификации пользователей на веб-сайте Icinga Web 2 мы используем защищённый протокол Kerberos, дополнительно усилить сессионную защиту HTTP-соединений с помощью SSL всё же не будет лишним.
Для этого нам потребуется сделать пару несложных вещей – активировать модуль веб-сервера для поддержки SSL (mod_ssl) и сгенерировать SSL-сертификат веб-сервера, который в последствии в паре с закрытым ключом от этого сертификата нужно будет привязать к конфигурации веб-сервера.
Модуль поддержки SSL в Apache на Debian установлен в конфигурации по умолчанию, поэтому нам остаётся только активировать его (при активации этого модуля будет активирован ряд других вспомогательных модулей):
# a2enmod ssl
Considering dependency setenvif for ssl:
Module setenvif already enabled
Considering dependency mime for ssl:
Module mime already enabled
Considering dependency socache_shmcb for ssl:
Enabling module socache_shmcb.
Enabling module ssl.
See /usr/share/doc/apache2/README.Debian.gz on how to configure SSL and create self-signed certificates.
To activate the new configuration, you need to run:
service apache2 restart
Убедимся в том, что модуль SSL отображается в списке активированных модулей
# apache2ctl -M | grep ssl
ssl_module (shared)
По поводу генерации закрытого ключа и сертификата для веб-сервера Apache, опять же, я повторяться не буду, так как подобная процедура рассматривалась ранее, например, в заметке Установка сертификата от Windows Server CA на веб-сервер Apache. Предполагая, что у нас уже есть на руках готовые файлы ключа и сертификата в формате PEM размещаем их на нашем сервере Icinga Web 2 в каталогах /etc/ssl/private/ и /etc/ssl/certs/ соответственно.
# mv ~/KOM-AD01-MON20.key /etc/ssl/private/
# mv ~/KOM-AD01-MON20.pem /etc/ssl/certs/
# chmod 640 /etc/ssl/private/KOM-AD01-MON20.key
# chown root:www-data /etc/ssl/private/KOM-AD01-MON20.key
Теперь нам остаётся лишь исправить конфигурацию веб-сайта Icinga Web 2 в Apache, таким образом, чтобы обязательно использовался протокол HTTPS. В итоге конфигурационный файл /etc/apache2/conf-available/icingaweb2.conf примет примерно следующий вид:
<VirtualHost *:80>
ServerName "KOM-AD01-MON20.holding.com"
RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteRule ^/?(.*) https://%{SERVER_NAME}/$1 [R,L]
</VirtualHost>
<VirtualHost *:443>
ServerName "KOM-AD01-MON20.holding.com"
DocumentRoot "/var/www/html"
SSLEngine on
SSLCertificateFile "/etc/ssl/certs/KOM-AD01-MON20.pem"
SSLCertificateKeyFile "/etc/ssl/private/KOM-AD01-MON20.key"
Alias /icingaweb2 "/usr/share/icingaweb2/public"
<Directory "/usr/share/icingaweb2/public">
AuthType Kerberos
AuthName "Kerberos Login"
Krb5Keytab /etc/apache2/s-Icinga-Apache-Krb.keytab
KrbAuthRealms HOLDING.COM
KrbMethodK5Passwd on
Require pam-account apache2-icingaweb2
ErrorDocument 401 /IcingaUnauthorized.html
Options SymLinksIfOwnerMatch
AllowOverride None
SetEnv ICINGAWEB_CONFIGDIR "/etc/icingaweb2"
EnableSendfile Off
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteBase /icingaweb2/
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ index.php [NC,L]
</IfModule>
<IfModule !mod_rewrite.c>
DirectoryIndex error_norewrite.html
</IfModule>
</Directory>
</VirtualHost>
После внесённых изменений в конфигурацию Apache, произведём перезапуск службы:
# systemctl restart apache2
Теперь наш веб-сайт Apache имеет не только возможность безопасной и удобной аутентификации и авторизации доменных пользователей AD, но и имеет дополнительную защиту всех HTTP-соединений.
Однако, хочу отметить, что не смотря на полученное удобство аутентификации в таком решении имеется своя "ложка дегтя", хоть и несущественная (при условии нормальной работы Kerberos). Дело в том, что Icinga Web 2 спроектирована таким образом, что в процессе аутентификации пользователя предполагается последовательный перебор подключенных методов аутентификации из ранее упомянутого файла /etc/icingaweb2/authentication.ini. То есть, порядок следования секций в этом файле, описывающих тот или иной аутентификатор прямо влияет на последовательность вызова соответствующих методов аутентификации. Однако, у меня пока не получилось настроить откат на использование встроенной Form-based аутентификации (с использованием локальных учётных записей из базы данных Icinga Web 2) в том случае, если по какой-то причине не отрабатывает внешняя Kerberos аутентификация в Apache. В общем вопрос отката на встроенную аутентификацию пока остался открытым.
Отладка
В процессе настройки конфигурации Icinga Web 2 могут возникнуть ситуации неопределённости, разрешить которые может помочь включение расширенного логирования. Для этого откроем веб-консоль и перейдём в Configuration > Application. Здесь на закладке General мы можем изменить уровень логирования в поле Logging Level и подсмотреть имя лог-файла, в который будет вестись логирование.
Если веб-консоль уже недоступна по причине "очумелых ручек", то включить расширенное логирование можно методом прямой правки конфигурационного файла /etc/icingaweb2/config.ini с изменением соответствующих параметров в секции [logging]:
...
[logging]
log = "file"
level = "DEBUG"
file = "/var/log/icingaweb2/icingaweb2.log"
...
Дополнительные источники информации:
Вот или лыжи не едут или одно из двух. Туплю и не могу понять в каком моменте. Взял свежий дебиан 9.0, ввел его в домен, вроде бы все настроил и работает за исключением сквозной авторизации. В Дебиан логинюсь под доменной учеткой, сама icinga видит доменные группы и никаких проблем быть не должно. Но при входе в админку icinga натыкаюсь на предложение авторизации от Апача, который не принимает пароль.
По мануалу прошел уже 3 раза, ни как не могу обнаружить в чем проблема. Можете подсказать, на каком этапе что-то могло пойти не так.