MAATRIX / Блог / OpenLDAP на сервере: частые ошибки и решения

OpenLDAP на сервере: частые ошибки и решения

MAATRIX

OpenLDAP — каталог, который пережил и Active Directory, и десяток модных SSO-решений, и продолжает тихо работать там, где нужен один источник правды для пользователей: почта, VPN, Wi-Fi, легаси-приложения без OIDC. Расплата за универсальность — конфигурация через cn=config вместо привычного файла, невнятная "Invalid DN syntax" без указания, какая часть DN не так, и ACL, которые молча режут доступ, а не сообщают об отказе. Разберём частые проблемы установки и эксплуатации slapd — от отказа стартовать до расхождения реплик — и что с ними делать, не переустанавливая всё с нуля.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

slapd не стартует или падает сразу после запуска

Первый диагностический шаг всегда один — смотреть не в systemctl status, а в подробный лог демона:

systemctl status slapd
journalctl -u slapd -n 50 --no-pager

Если systemctl status показывает failed без внятной причины, запустите slapd вручную в foreground-режиме — так видно, на какой строке конфигурации он спотыкается: slapd -d -1 -u openldap -g openldap.

Самая частая причина отказа старта на свежей установке — конфликт между старым файловым slapd.conf и новой конфигурацией cn=config (OLC, On-Line Configuration). Начиная с версии 2.4 конфигурация по умолчанию хранится в /etc/ldap/slapd.d/ как набор LDIF-записей, а не в одном текстовом файле, и если на сервере остались следы обоих подходов — демон откажется стартовать с невнятной ошибкой:

# проверить, какой режим активен
ls -la /etc/ldap/slapd.d/
# если каталог пуст, но slapd.conf существует — конвертируем
slaptest -f /etc/ldap/slapd.conf -F /etc/ldap/slapd.d/

Вторая типовая причина — права на каталоги с данными. База Berkeley DB (bdb) или MDB (mdb, используется по умолчанию в актуальных сборках) должна принадлежать пользователю openldap, и если вы разворачивали данные из бэкапа через root, права слетают:

chown -R openldap:openldap /var/lib/ldap
chmod 700 /var/lib/ldap

Третий вариант — порт 389 (или 636 для LDAPS) уже занят другим процессом, чаще всего осиротевшим предыдущим slapd: проверьте ss -tlnp | grep -E ':389|:636'.

"Invalid DN syntax" и "No such object" при ldapadd/ldapmodify

Эти две ошибки — источник, пожалуй, половины вопросов новичков в OpenLDAP, и обе почти никогда не значат то, что кажется на первый взгляд.

Invalid DN syntax почти всегда означает не опечатку в самом DN, а нарушение синтаксиса LDIF-файла — чаще всего лишний пробел после двоеточия там, где его не должно быть, либо неверный порядок атрибутов в dn::

# неверно — DN должен идти одной строкой без переноса
dn: uid=ivan,
 ou=people,dc=example,dc=com

# верно
dn: uid=ivan,ou=people,dc=example,dc=com
objectClass: inetOrgPerson
objectClass: posixAccount
uid: ivan
cn: Ivan Petrov
sn: Petrov

Проверяйте LDIF перед отправкой dry-run'ом: ldapadd -x -D "cn=admin,dc=example,dc=com" -W -f user.ldif -c -n — флаг -n не пишет данные, только проверяет синтаксис.

No such object (код 32) означает, что родительский узел для добавляемой записи ещё не существует. Частая ошибка новичков — попытка добавить uid=ivan,ou=people,dc=example,dc=com, когда сама ou=people ещё не создана. Дерево строится строго сверху вниз:

dn: ou=people,dc=example,dc=com
objectClass: organizationalUnit
ou: people

dn: ou=groups,dc=example,dc=com
objectClass: organizationalUnit
ou: groups

Отдельно стоит "Object class violation" (код 65) — вы задали objectClass: posixAccount, но не указали все его обязательные (MUST) атрибуты вроде uidNumber, gidNumber, homeDirectory. Требуемые атрибуты конкретного objectClass видно в схеме: ldapsearch -x -D "cn=admin,cn=config" -W -b cn=schema,cn=config '(cn={*}posixaccount)' olcObjectClasses.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

"Insufficient access" и проблемы с ACL

Если поиск или запись отдаёт Insufficient access (50), хотя вы вроде бы биндитесь под административной учёткой — почти всегда дело в ACL, а не в правах на файлы. Правила доступа проверяются построчно сверху вниз, и первое совпавшее побеждает — если общее правило стоит выше специфичного, специфичное никогда не сработает. Посмотреть текущие ACL: ldapsearch -Y EXTERNAL -H ldapi:/// -b cn=config olcAccess.

Типовая рабочая схема — админ читает и пишет всё, пользователь меняет свой пароль, остальные читают публичные атрибуты:

olcAccess: {0}to attrs=userPassword
  by self write
  by anonymous auth
  by dn="cn=admin,dc=example,dc=com" write
  by * none
olcAccess: {1}to *
  by dn="cn=admin,dc=example,dc=com" write
  by self read
  by * read

Обновление ACL через ldapmodify -Y EXTERNAL -H ldapi:/// в режиме OLC требует точного номера правила в фигурных скобках ({0}, {1}) — промахнётесь с индексом, замените не то правило, что имели в виду.

Отдельная ловушка — анонимный bind. Если он не отключён явно, любой клиент может делать ldapsearch без пароля и читать записи под общим by * read. Проверьте и при необходимости запретите:

dn: cn=config
changetype: modify
replace: olcDisallows
olcDisallows: bind_anon

TLS и StartTLS: ошибки сертификатов и незашифрованный трафик

По умолчанию свежеустановленный OpenLDAP слушает обычный ldap:// на 389 порту без шифрования — пароли и данные идут открытым текстом внутри локальной сети, что для боевого сервера неприемлемо. Настройка TLS у slapd делается через cn=config, а не через отдельный конфиг-файл:

ldapmodify -Y EXTERNAL -H ldapi:/// <<EOF
dn: cn=config
changetype: modify
replace: olcTLSCertificateFile
olcTLSCertificateFile: /etc/ldap/certs/server.crt
-
replace: olcTLSCertificateKeyFile
olcTLSCertificateKeyFile: /etc/ldap/certs/server.key
-
replace: olcTLSCACertificateFile
olcTLSCACertificateFile: /etc/ldap/certs/ca.crt
EOF

Самая частая ошибка после этого — TLS: can't accept: certificate not usable в логах. Причина в 9 случаях из 10 — приватный ключ недоступен пользователю openldap, потому что сертификаты выпустил Let's Encrypt через certbot, а права на /etc/letsencrypt/live/ стандартно root-only. Надёжнее всего — копировать сертификаты в отдельный каталог с явными правами под openldap после каждого обновления certbot через deploy-hook, а не открывать доступ к /etc/letsencrypt/ напрямую.

Проверить, что StartTLS реально работает, а не просто настроен: ldapsearch -x -ZZ -H ldap://ldap.example.com -b dc=example,dc=com -s base — флаг -ZZ требует успешного StartTLS и завершится ошибкой, а не тихим фолбэком, если что-то не так.

Если клиенты жалуются на TLS: hostname does not match CN in peer certificate — сертификат выпущен на одно имя, а клиент обращается по другому (IP вместо FQDN, короткое имя без домена). LDAP обычно не прощает такие расхождения без явного TLS_REQCERT allow на стороне клиента, что само по себе снижает безопасность и годится только как временный костыль для диагностики.

Репликация (syncrepl) расходится между узлами

Классическая multi-master или master-consumer репликация строится на syncrepl и живёт надёжно, пока не столкнётся с сетевым разрывом дольше времени хранения журнала изменений — тогда узлы расходятся.

Проверить текущее состояние синхронизации на каждом узле — сравнить contextCSN:

ldapsearch -x -D "cn=admin,dc=example,dc=com" -W \
  -b dc=example,dc=com -s base contextCSN

Если значения contextCSN на мастере и консьюмере расходятся и не сближаются со временем — типичная причина в том, что accesslog-база на мастере (при delta-syncrepl) уже перезаписала нужные записи журнала раньше, чем консьюмер успел их забрать после разрыва связи. Решение — либо увеличить olcAccessLogPurge interval, либо для сильно отставшего узла проще остановить slapd, очистить /var/lib/ldap/* и запустить заново: consumer сам запросит полный refresh у provider'а согласно конфигурации syncrepl.

Ещё одна частая ошибка — расхождение olcServerID между узлами в multi-master схеме. Каждый узел обязан иметь уникальный ID, и если два сервера по недосмотру получили одинаковый при клонировании VM, реплика формально "работает", но конфликты записи разрешаются непредсказуемо. Логи репликации смотрите отдельно от общих логов slapd, включив уровень sync в olcLogLevel — иначе проблемы репликации тонут среди обычных операций.

Медленные поиски и проблемы с индексами

Если ldapsearch по большой базе (десятки тысяч записей) занимает секунды вместо миллисекунд, а нагрузка на CPU невысокая — почти всегда не хватает индекса на атрибуте фильтрации. OpenLDAP не строит индексы автоматически под произвольные запросы. Посмотреть текущие: ldapsearch -Y EXTERNAL -H ldapi:/// -b cn=config '(olcDatabase={1}mdb)' olcDbIndex. Базовый набор, который закрывает большинство сценариев аутентификации и поиска:

dn: olcDatabase={1}mdb,cn=config
changetype: modify
replace: olcDbIndex
olcDbIndex: objectClass eq
olcDbIndex: uid eq
olcDbIndex: cn,sn,mail eq,sub
olcDbIndex: uidNumber,gidNumber,memberUid eq

После изменения индексов их нужно физически перестроить — просто добавить olcDbIndex в конфиг недостаточно, если база уже содержит данные: остановите slapd, выполните slapindex -F /etc/ldap/slapd.d -b dc=example,dc=com, верните права chown -R openldap:openldap /var/lib/ldap и запустите демон заново.

Отдельно проверьте olcDbMaxSize для MDB-бэкенда — это заранее заданный лимит, до которого может вырасти файл data.mdb, он не растёт автоматически бесконечно. Если лимит выставлен слишком маленьким (частая история при переносе с bdb, где такого параметра не было), запись начнёт падать с Out of space задолго до реального заполнения диска — увеличьте olcDbMaxSize через тот же ldapmodify.

Бэкап и восстановление без потери схемы

Самая надёжная резервная копия OpenLDAP — не бэкап директории /var/lib/ldap напрямую (файл MDB может оказаться в промежуточном состоянии при копировании на горячую), а экспорт через slapcat, который выгружает и данные (slapcat -n 1 -l ldap-data.ldif), и конфигурацию cn=config (slapcat -n 0 -l ldap-config.ldif) в LDIF.

Восстановление делается через slapadd при остановленном демоне — попытка писать в базу через slapadd, пока slapd активен, приведёт к повреждению файла: systemctl stop slapd, очистка /var/lib/ldap/*, slapadd -n 1 -l backup.ldif, возврат прав chown -R openldap:openldap /var/lib/ldap и запуск заново.

Держите отдельно бэкап конфигурации cn=config — без неё восстановление даст рабочий, но "голый" каталог без ваших ACL и индексов. Планируйте ежедневный slapcat по cron с ротацией и храните копию за пределами сервера — единственный дамп на том же диске не спасёт при отказе диска.

Если каталог используется как источник для SSH-аутентификации через PAM/NSS, полезно добавить двухфакторную аутентификацию SSH поверх LDAP-логина — это заметно снижает риск при утечке пароля из каталога. Если вместо классического LDAP вы рассматриваете более современный SSO-слой поверх того же каталога пользователей, посмотрите на разбор ошибок Authentik — он умеет подключаться к OpenLDAP как к источнику через LDAP Source и закрывает многое из того, что в чистом LDAP приходится делать руками. Общие вопросы управления учётками на самом сервере разобраны в статье про управление пользователями и группами в Linux — пригодится, если LDAP синхронизируется с локальными учётками через nss-pam-ldapd или sssd.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

Чем cn=config лучше старого slapd.conf и стоит ли мигрировать существующую установку?

cn=config меняется на лету через ldapmodify без перезапуска демона и хранит историю изменений как обычные записи каталога. Для новой установки используйте только его; старую конвертирует slaptest -f slapd.conf -F slapd.d/, но перед этим сделайте slapcat на всякий случай.

Можно ли использовать OpenLDAP вместе с Active Directory в одной инфраструктуре?

Да, через syncrepl в режиме одностороннего pull из AD — но лучше как временный мост при миграции, а не постоянную архитектуру: два источника правды рано или поздно разойдутся. Для VPN-аутентификации через AD проще смотреть в сторону прямой интеграции VPN с Active Directory через NPS, не поднимая OpenLDAP как посредника.

Почему ldapsearch с ldapi:/// работает без пароля, а обычный ldap:// требует bind?

ldapi:/// — Unix-сокет, доступ к которому регулируется правами файловой системы; при SASL EXTERNAL сервер доверяет уже проверенной ОС личности процесса. Это нормальное поведение, если права на сокет не ослаблены вручную.

Сколько RAM закладывать под OpenLDAP на несколько тысяч пользователей?

Для базы на 5-10 тысяч записей хватает 1-2 ГБ RAM — MDB построена на memory-mapped файлах и активно использует файловый кэш ОС, так что аппетит растёт скорее с размером базы, чем линейно с числом пользователей.

Нужно ли включать анонимный bind для работы NSS/PAM-клиентов?

Нет — создайте служебную учётку только для чтения (cn=svc-nsspam,ou=service,dc=example,dc=com) с ACL на нужные атрибуты и используйте её bind DN в /etc/nslcd.conf или sssd.conf. Анонимный доступ к каталогу — ненужный риск раскрытия структуры организации.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →