Каталог LDAP - это сетевая база с иерархическими записями, заточенная под чтение: учётки пользователей, группы, хосты, сертификаты, настройки приложений. Задача администратора в этом уроке - поднять slapd, настроить его через современную динамическую конфигурацию cn=config, спроектировать дерево записей (DIT), залить данные через LDIF, ускорить поиск индексами, закрыть доступ через ACL, наладить репликацию syncrepl и снять корректный бэкап. Это фундамент, на котором потом строятся SSSD, почта, Samba и единый вход.

Как это работает
Каталог - это дерево записей (DIT, Directory Information Tree). Каждая запись имеет уникальное имя DN (Distinguished Name), собранное из RDN снизу вверх, например uid=anna,ou=people,dc=lab,dc=local. Запись состоит из атрибутов, а набор разрешённых атрибутов и обязательных среди них задаёт objectClass. Сами объектные классы и атрибуты описаны в схемах (schema): inetOrgPerson, posixAccount, groupOfNames и так далее. Без подключённой схемы сервер отвергнет запись с неизвестным атрибутом - это не бюрократия, а гарантия целостности данных.
Раньше slapd читал текстовый slapd.conf и требовал перезапуска на каждое изменение. С версии 2.3 действует динамическая конфигурация: сам сервер хранится как поддерево cn=config и правится онлайн через LDAP-операции, без рестарта. Физически это каталог /etc/openldap/slapd.d (RHEL) или /etc/ldap/slapd.d (Debian) с LDIF-файлами, но руками их трогать нельзя - только через ldapmodify к сокету ldapi:///. Схемы тоже стали частью cn=config (ветка cn=schema,cn=config), а не отдельными include.
Бэкенд хранения по умолчанию сейчас mdb (LMDB) - memory-mapped база, быстрая и без отдельной возни с кешами, она заменила устаревший hdb/bdb. Поиск в каталоге без индекса - это линейный перебор всех записей, поэтому атрибуты, по которым ищут (uid, cn, mail, member), индексируют. Доступ режут ACL: правила вида "к каким записям и атрибутам, кому, какой уровень" применяются сверху вниз, и первое подошедшее правило выигрывает - порядок критичен. Репликация делается через syncrepl: реплика-потребитель подписывается на изменения у поставщика и подтягивает их, отслеживая состояние через cookie и значения contextCSN.
Команды и примеры
Установка и запуск. Debian/Ubuntu кладёт сервер в пакет slapd, утилиты в ldap-utils:
Код: Выделить всё
# Debian 13 / Ubuntu 24.04
apt install slapd ldap-utils
dpkg-reconfigure slapd # переспросит домен, пароль admin, базу
# RHEL 10 / Fedora 41+
dnf install openldap-servers openldap-clients
systemctl enable --now slapd
Код: Выделить всё
ldapsearch -Y EXTERNAL -H ldapi:/// -b cn=config dn
ldapsearch -Y EXTERNAL -H ldapi:/// -b cn=schema,cn=config dn
Код: Выделить всё
ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/cosine.ldif
ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/inetorgperson.ldif
Код: Выделить всё
# base.ldif
dn: dc=lab,dc=local
objectClass: dcObject
objectClass: organization
o: Lab
dc: lab
dn: ou=people,dc=lab,dc=local
objectClass: organizationalUnit
ou: people
dn: uid=anna,ou=people,dc=lab,dc=local
objectClass: inetOrgPerson
objectClass: posixAccount
cn: Anna Petrova
sn: Petrova
uid: anna
uidNumber: 10001
gidNumber: 10001
homeDirectory: /home/anna
userPassword: {SSHA}...
Код: Выделить всё
ldapadd -x -D cn=admin,dc=lab,dc=local -W -f base.ldif
slappasswd -h '{SSHA}' # сгенерировать хеш для userPassword
Код: Выделить всё
# index.ldif
dn: olcDatabase={1}mdb,cn=config
changetype: modify
add: olcDbIndex
olcDbIndex: uid eq
olcDbIndex: cn,mail eq,sub
olcDbIndex: member eq
Код: Выделить всё
ldapmodify -Y EXTERNAL -H ldapi:/// -f index.ldif
# для старых данных пересобрать индекс на остановленном slapd:
systemctl stop slapd && slapindex && systemctl start slapd
Код: Выделить всё
dn: olcDatabase={1}mdb,cn=config
changetype: modify
replace: olcAccess
olcAccess: {0}to attrs=userPassword by self write by anonymous auth by * none
olcAccess: {1}to * by self read by users read by * none
Код: Выделить всё
slapcat -n 1 -l data.ldif # дамп данных
slapcat -b cn=config -l config.ldif # дамп конфигурации
# восстановление: slapadd на пустой остановленной базе
slapadd -n 1 -l data.ldif
- Правка файлов в slapd.d вручную - сервер их перезапишет или перестанет стартовать. Только ldapmodify через ldapi:///.
- Забыли подключить схему - получаете ошибку "objectClass: value #N invalid per syntax" или "attribute type undefined". Сначала схема, потом данные.
- slapcat запущен параллельно с пишущим slapd на старых бэкендах даёт битый дамп. На mdb читать безопаснее, но для гарантии останавливайте сервис или используйте онлайн-метод.
- ACL пишут от частного к общему: правило "to *" поставленное первым перекрывает все последующие, доступ к паролям ломается.
- Изменили индексы, но не пересобрали slapindex - новые данные индексируются, старые ищутся перебором, поиск "тормозит выборочно".
- Репликация молчит - забыли создать на реплике учётку для биндинга или не открыли порт 389/636; сверяйте contextCSN на обоих узлах.
- Перепутали authentication при bind: для cn=config почти всегда EXTERNAL по сокету, для данных - simple bind с -x -D -W.
- Установите slapd и клиентские утилиты, проверьте, что сервис активен и слушает 389.
- Через ldapsearch -Y EXTERNAL по cn=config найдите имя своей базы данных (olcDatabase={N}mdb) и текущий suffix.
- Создайте base.ldif с корнем dc=lab,dc=local, ou=people и одним пользователем (хеш пароля через slappasswd), залейте ldapadd.
- Добавьте индексы для uid и mail через ldapmodify, при необходимости остановите сервис и выполните slapindex.
- Настройте ACL так, чтобы пользователь менял только свой userPassword, а читали запись только аутентифицированные; проверьте ldapwhoami и ldappasswd.
- Снимите бэкап данных и конфигурации через slapcat в два файла, удалите тестовую запись и восстановите её из дампа.
- Чем динамическая конфигурация cn=config принципиально отличается от slapd.conf и почему нельзя редактировать файлы в slapd.d напрямую?
- Как из распределения DN собирается дерево DIT и какую роль играет objectClass при добавлении записи?
- Какой механизм авторизации используется при правке cn=config через ldapi:/// и почему не нужен пароль?
- Зачем нужен slapindex и в каком случае одного добавления olcDbIndex недостаточно?
- В каком порядке slapd применяет правила olcAccess и к чему приводит ошибочный порядок для атрибута userPassword?
- Чем отличается syncrepl-потребитель от поставщика и по каким атрибутам контролируют консистентность реплик?