Этот пост я хочу посвятить кейсу с крупного ИТ-проекта, который делала наша компания. В рамках проекта внедрялось большое количество сервисов, и для них нужно было обеспечить LDAP-аутентификацию при следующих операциях:
Доступ в GUI-интерфейсы сервисов.
Доступ по SSH на серверы, где функционируют сервисы, с ограничением доступа на основании членства пользователей в группах LDAP-каталога.
У заказчика уже была развернута служба каталогов Microsoft Active Directory. Требованием проекта было отсутствие прямого доступа между внедряемыми сервисами и AD. На стороне сервисов не должны были прописываться параметры сервисных учетных записей AD. Кроме того, сетевой доступ к контроллеру MS AD был разрешен только для одного хоста.
Под катом — подробности о том, как мы решили эту задачу.
Для решения данной задачи был выбран OpenLDAP в режиме проксирования аутентификационных запросов в сторону контроллеров MS AD. Для входа на серверы был использован модуль SSSD, обрабатывающий LDAP(S)-запросы с дополнительной фильтрацией по группам MS Active Directory.
Задача проксирования запросов через OpenLDAP не выглядит чем-то сложным. В Интернете достаточно информации на эту тему. Загвоздка была в том, что в основном они описывают выполнение конфигурации OpenLDAP через файл sladp.conf. Однако начиная с версии OpenLDAP 2.4 настройка происходит не с помощью slapd.conf, а через конфигурационный контекст LDAP cn=config. Вариант настройки через slapd.conf устарел и более не поддерживается. В свободном доступе крайне мало похожих примеров настроек через cn=config.
В статье я постарался максимально подробно описать технику настройки OpenLDAP 2.6 и SSSD через cn=config на Rocky Linux 8.5 и рассказать, как мы решали возникающие в процессе проблемы.
Установка OpenLDAP
Для установки OpenLDAP нужно выполнить следующие действия:
1. Установить зависимости:
# dnf install wget vim cyrus-sasl-devel libtool-ltdl-devel openssl-devel libdb-devel make libtool autoconf tar gcc perl perl-devel -y
2. Подключить репозиторий Symas, чтобы скачать из него OpenLDAP:
#wget -q https://repo.symas.com/configs/SOFL/rhel8/sofl.repo -O /etc/yum.repos.d/sofl.repo
3. Установить серверную и клиентскую части OpenLDAP:
#dnf install symas-openldap-clients symas-openldap-servers -y
4. Добавить OpenLDAP (slapd.service) в автозагрузку и включить службу:
#systemctl enable slapd
#systemctl start slapd
Настройка OpenLDAP
На сервере OpenLDAP (в нашем примере opld.test.local) нужно выполнить следующие действия:
1. Внести информацию о BASE и URI в файл /etc/openldap:
BASE dc=test,dc=local
URI ldap://opld.test.local ldaps://opld.test.local:636
2. При работе OpenLDAP в режиме проксирования контроллер домена Microsoft Active Directory будет являться для OpenLDAP backend-базой данных LDAP-типа. Для возможности подключения OpenLDAP к контроллеру домена необходимо загрузить модуль back_ldap.
Для этого:
a. Убедиться в наличии файла back_ldap.la на сервере OpenLDAP. Если его нет, то на сервер OpenLDAP необходимо загрузить данную библиотеку.
b. Создать файл ldif в виде:
dn: cn=module,cn=config
objectClass: olcModuleList
cn: module
olcModulePath: /usr/lib64/openldap
olcModuleLoad: back_ldap.la
c. Загрузить back_ldap.ldif файл в конфигурацию сервера OpenLDAP:
#ldapadd -Y EXTERNAL -H ldapi:/// -f back_ldap.ldif
3. Создать backend-базу типа ldap, в качестве которой будет выступать Active Directory:
a. Создать файл ldap_db.ldif в виде:
dn: olcDatabase=ldap,cn=config
objectClass: olcDatabaseConfig
objectClass: olcLDAPConfig
olcDatabase: ldap
olcDbIDAssertBind: bindmethod="simple" binddn="CN=tech_test_local,OU=Tech
Accounts,DC=test,DC=local" credentials="password"
olcDbURI: ldaps://dc01.test.local
olcReadOnly: TRUE
olcRootDN: cn=openldap,dc=test,dc=local
olcRootPW: password
olcSuffix: dc=test,dc=local
olcDbChaseReferrals: FALSE
olcDbIDAssertBind: Указание метода подключения, distinguishedName и пароля УЗ для подключения к контроллеру MS Active Directory.
olcDbURI: URI контроллера AD.
olcReadOnly: Режим работы (чтение/запись) с MS Active Directory.
olcRootDN: Сервисная УЗ OpenLDAP. С помощью нее к OpenLDAP будут подключаться сервисы.
olcRootPW: Пароль от сервисной УЗ OpenLDAP.
olcSuffix: Суффикс домена.
olcDbChaseReferrals: Определяет возможность использования механизма отсылок.
Чтобы зашифровать пароль olcRootPW, выполнить команду:
# slappasswd -s password
и сгенерированное хэш-значение указать в атрибут olcRootPW.
b. На сервере OpenLDAP выполнить команду:
#ldapadd -Y EXTERNAL -H ldapi:/// -f ldap_db.ldif
4. Настроить защищенное TLS-соединение между OpenLDAP и AD.
Должны быть предоставлены цепочки сертификатов удостоверяющих центров, которые выпустили сертификаты для контроллера домена:
a. Положить цепочку сертификатов (cacerts.pem) на сервер OpenLDAP (например, в /etc/openldap/certs).
b. В файле /etc/openldap/ldap.conf указать путь к сертификату:
TLS_CACERT /etc/openldap/certs/cacerts.pem
5. Обеспечить возможность подключения сервисов к OpenLDAP по LDAPS:
a. Выпустить ключ и сертификат для сервера OpenLDAP. Положить сертификат (oldap.crt) и ключ (oldap.key) на сервер OpenLDAP (например, в /etc/openldap/certs).
b. Создать opldcert.ldif файл:
dn: cn=config
objectClass: olcDatabaseConfig
objectClass: olcLDAPConfig
olcDatabase: cn=config
changetype: add
olcTLSCertificateFile: /etc/openldap/certs/oldap.crt
olcTLSCertificateFileKey: /etc/openldap/certs/oldap.key
olcTLSVerifyClient: never
c. Выполнить команду:
#ldapadd -Y EXTERNAL -H ldapi:/// -f opldcert.ldif
На этом конфигурация OpenLDAP в режиме проксирования завершена. После завершения этой настройки сервер может обрабатывать LDAP/LDAPS входящие запросы от клиентов, производить проксирование запросов на контроллер домена MS Active Directory. Mежду сервером OpenLDAP и контроллером домена MS Active Directory настроено защищенное соединение.
Ниже опишу реализацию настройки модуля SSSD в части SSH-аутентификации на клиентские серверы с учетом фильтрации согласно членству в группах MS Active Directory.
Настройка службы SSSD
1. Установить пакеты SSSD:
# sudo yum install sssd-tools sssd oddjob oddjob-mkhomedir samba-common-tools
2. Настроить файл ldap.conf на клиентских серверах. Загружаем сертификат сервера OpenLDAP и прописываем путь к нему:
URI ldap://opld.test.local ldaps://opld.test.local:636
BASE dc=test,dc=local
TLS_CACERT /etc/openldap/certs/oldap.crt
TLS_CACERTDIR /etc/openldap/certs
<![if !supportLineBreakNewLine]>
<![endif]>
3. Создать файл sssd.conf. (etc/sssd/sssd.conf):
[domain/test.local]
ldap_schema = ad
id_provider = ldap
autofs_provider = ldap
auth_provider = ldap
chpass_provider = ldap
ldap_uri = ldaps://opld.test.local:636
ldap_search_base = dc=test,dc=local
ldap_id_use_start_tls = True
ldap_tls_cacertdir = /etc/openldap/certs
cache_credentials = False
ldap_tls_reqcert = allow
ldap_default_bind_dn = cn=openldap,dc=test,dc=local
ldap_default_authtok_type = obfuscated_password
ldap_default_authtok = #зашифровать и ввести в следующем шаге
ldap_access_order = filter
ldap_id_mapping = True
ldap_referrals = False
access_provider = ldap
ldap_access_filter = (|(memberOf= CN=Admins,DC=test,DC=local)(memberOf=CN=Support,DC=test,DC=local))
use_fully_qualified_names = False
# Object Mappings
ldap_user_object_class = user
ldap_user_name = sAMAccountName
ldap_group_object_class = group
ldap_group_name = cn
# ID Mappings
ldap_user_objectsid = objectSid
ldap_group_objectsid = objectSid
ldap_idmap_range_size = 1048576
ldap_user_primary_group = primaryGroupID
override_homedir = /mnt/home/%u
default_shell = /bin/bash
fallback_homedir = /home/%u@%d
[sssd]
config_file_version = 2
services = nss, pam,autofs
domains = test.local
[nss]
homedir_substring = /home
В примере ниже я использовал параметр ldap_acсess_filter с группами AD (Admins, TechSupport). Подключиться к серверу смогут только те пользователи, кто состоит в этих MS AD группах.
4. Дать права файлу sssd.conf:
# chmod 600 /etc/sssd/sssd.conf
5. Чтобы пароль не хранился в открытом в виде, зашифровать его:
# sss_obfuscate -d test.local
6. Внести в файл /etc/hosts или настроить адрес OpenLDAP на вашем DNS-сервере:
# (IP OpenLDAP) opld.test.local
7. Перезапустить sssd, проверить работу службы с помощью команды id:
# systemctl restart sssd.service
#id {username}
#User Found (id=1234567) # Пример вывода строки, найденного пользователя
8. Переключить профиль входа в Linux на использование sssd (LDAP-аутентификация):
# authselect select sssd --force
9. Настроить sudo права для доменных УЗ:
# echo "sudoers: files sss" >> /etc/nsswitch.conf
10. Обеспечить создание домашних директорий для доменных пользователей:
# systemctl enable --now oddjobd
# echo "session optional pam_oddjob_mkhomedir.so skel=/etc/skel/ umask=0022" >> /etc/pam.d/system-auth
# systemctl restart oddjobd
11. Проверить работу SSSD:
# sssctl domain-status test.local
12. Если вы получаете вывод подобного рода, то SSSD настроен корректно, можно попробовать аутентифицироваться на сервер:
# sssctl domain-status test.local
Online status: Online
Active servers:
LDAP: test.local
Discovered LDAP servers:
- test.local
Если вы получаете статус Offline, значит, на каком-то этапе выше вы допустили ошибку, проверяйте заново.
Проблемы и решение
После подключения одной из систем и настройки LDAP-аутентификации обнаружили проблему, что аутентификация в Web UI не проходила. Такая же проблема была замечена при попытке аутентификации по SSH. Сессия на аутентификацию отваливалась по тайм-ауту. Такое поведение обнаруживалось, если осуществлялся поиск по всему домену. При этом, если мы сужали границы поиска, например, на уровень только определенной OU, то проблема уходила, и пользователи могли аутентифицироваться.
Были сняты дампы обращений клиента к OpenLDAP и OpenLDAP к MS AD. Из них выяснили, что при поиске по всему домену, помимо ответа на запрос, было обращение к DomainDNSZones с помощью механизма отсылок (Referrals).
Отсылка — это процесс, посредством которого LDAP-сервер, вместо того чтобы вернуть результат запроса, возвращает ссылку (отсылку, referral) на другой LDAP-сервер или, в нашем случае, домен-контроллер, который может содержать дополнительную информацию. Получая referral на DomainDNSZones, OpenLDAP выполнял запрос контроллерам домена MS AD, к которым не было сетевого доступа. В связи с этим висела сессия от сервера OpenLDAP к MS AD, и далее она обрывалась по тайм-ауту.
Соответственно, для решения проблемы нужно было найти способ управления рефералами. В основном все статьи, связанные с данной проблемой, описывали настройки с помощью конфигурационного файла slapd.conf, а не cn=config.
Исследуя схему OpenLDAP, был найден параметр olcDbChaseReferrals, который как раз и отвечал за отсылки при обращении к MS AD. Если использовать значение olcDbChaseReferrals=FALSE, то LDAP, получая referral на DomainDNSZones, игнорирует это и не обращается к прочим контроллерам домена.
В документации к SSSD мы также обнаружили параметр, отвечающий за отсылки — ldap_referrals. После применения этого параметра со значением FALSE SSSD перестал падать и терять соединение с контроллером домена.
Еще один интересный момент, который мы заметили, был связан с настройкой фильтрации доступа на основе членства в группах AD. Мы увидели, что после настройки фильтра пользователи не могли получить доступ к серверу. Проблема заключалась в том, что при вычитывании объектов из SSSD им не назначался корректный уникальный ID. ID генерировался самой Linux-машиной, а должен был быть получен в атрибуте objectSID из MS Active Direсtory. Таким образом, SSSD не мог получить корректный список AD-групп, в которые входит пользователь (SSSD должен сопоставлять идентификаторы пользователей и групп из атрибутов ldap_user_objectsid и ldap_group_objectsid вместо того, чтобы полагаться на сгенерированные Linux’ом ID). Решением проблемы стало использование параметр ldap_id_mapping со значением TRUE.
Надеюсь, этот пост был полезным и помог решить задачи быстрее. Если у кого-то есть подобный опыт в настройках, делитесь вашими знаниями, буду готов обновить и дополнить статью свежей информацией.
Автор поста: старший пресейл-инженер Владислав Алешин