Этот пост я хочу посвятить кейсу с крупного ИТ-проекта, который делала наша компания. В рамках проекта внедрялось большое количество сервисов, и для них нужно было обеспечить 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.

Надеюсь, этот пост был полезным и помог решить задачи быстрее. Если у кого-то есть подобный опыт в настройках, делитесь вашими знаниями, буду готов обновить и дополнить статью свежей информацией.

Автор поста: старший пресейл-инженер Владислав Алешин

Комментарии (4)


  1. sergeyns
    10.04.2023 08:45
    +1

    Ну так не интересно. Как будто у заказчика один контроллер домена в вакууме)))


  1. Coler95
    10.04.2023 08:45

    Автор молодец! Очень позновательно


  1. Abyss777
    10.04.2023 08:45

    Хочется странного ...

    Есть много доменов, разной степени старости, на большинстве из них нет LDAPS, но включен DIGEST-MD5.

    Большая часть линукс приложений не умеют DIGEST-MD5 авторизацию.

    Можно ли так сконфигурировать OpenLDAP чтоб он принимал голый BIND запрос по LDAP, и передавал его в AD с DIGEST-MD5 авторизацией?

    Мне не удалось, он либо BIND передаёт как есть, либо авторизуется с rootDN.


  1. Vasily_Pechersky
    10.04.2023 08:45
    +1

    Вообще есть решение в виде Keycloak и его альтернатив. Как раз аутентификация для сервисов с возможностью синхронизации с MS AD.