OpenLDAP сервер

Легковесный протокол доступа к каталогам, или LDAP - это протокол запросов и изменений к сервису каталогов на базе X.500, работающий поверх TCP/IP. Текущая версия LDAP это LDAPv3, как определено в RFC4510, а реализация LDAP в Ubuntu - это OpenLDAP, текущей версии 2.4.25 (Oneiric) (2.4.28 для Precise - прим. переводчика).

Итак, этот протокол обеспечивает доступ к каталогам LDAP. Здесь приведены некоторые ключевые понятия и термины:

  1. LDAP каталог - это дерево данных в виде записей, иерархичных по своей натуре, называемое Дерево каталогов информации (DIT).

  2. Запись содержит набор атрибутов.

  3. Атрибут имеет тип (имя/описание) и одно или несколько значений.

  4. Каждый атрибут должен быть определен как минимум в одном objectClass.

  5. Атрибуты и объектные классы определяются в схемах (объектный класс фактически рассматривается как специальный вид атрибута).

  6. Каждая запись имеет уникальный идентификатор: свое Отличительное имя (DN или dn). Она состоит из своего Относительного отличительного имени (RDN), следующим за записью родительского DN.

  7. DN записи - это не атрибут. Оно не является рассматриваемой частью собственно записи.

Термины объект, контейнер и узел (node) имеют определенный подтекст, но они все по существу обозначают такую вещь, как запись, технически корректный термин.

Например, далее мы имеем одну запись, содержащую 11 атрибутов. Ее DN - это "cn=John Doe,dc=example,dc=com"; ее RND - это "cn=John Doe"; а родительский DN - "dc=example,dc=com".

 dn: cn=John Doe,dc=example,dc=com
 cn: John Doe
 givenName: John
 sn: Doe
 telephoneNumber: +1 888 555 6789
 telephoneNumber: +1 888 555 1232
 mail: john@example.com
 manager: cn=Larry Smith,dc=example,dc=com
 objectClass: inetOrgPerson
 objectClass: organizationalPerson
 objectClass: person
 objectClass: top

Вышеприведенная запись - это формат LDIF (формат обмена данными LDAP). Любая информация, которую вы помещаете в ваш DIT должна быть в таком формате. Это определено в RFC2849.

Хотя данное руководство описывает как использовать это для централизованной идентификации, LDAP хорош для всего, что затрагивает большое количество запросов к системе, основанной на атрибутах (имя:значение) и ориентированной преимущественно на чтение. В качестве примеров можно привести адресную книгу, список адресов email и конфигурация почтового сервера.

Установка

Установка сервиса сервера OpenLDAP и привычных утилит управления LDAP. Они находятся в пакетах slapd и ldap-utils соответственно.

Установка slapd создаст работающую конфигурацию. В частности она создаст экземпляр базы данных, которую вы можете использовать для хранения своих данных. Однако суффикс (или базовый DN) этого экземпляра будет определен из доменного имени localhost. Если вы хотите использовать что-то другое, отредактируйте /etc/hosts и замените доменное имя на подходящее. В качестве примера, если вам нужен суффикс dc=example,dc=com, то ваш файл должен иметь подобную строку:

127.0.1.1       hostname.example.com	hostname

Вы можете отменить изменения после установки пакета.

Это руководство будет использовать суффикс базы данных dc=example,dc=com.

Продолжим с установкой:

sudo apt-get install slapd ldap-utils

Начиная с Ubuntu 8.10 slapd проектируется, чтобы настраиваться самостоятельно, выделяя отдельный DIT для этой цели. Это позволяет динамически настраивать slapd без необходимости перестартовывать сервис. Эта конфигурационная база данных содержит коллекцию текстовых LDIF файлов, расположенных в /etc/ldap/slapd.d. Этот вариант работы известен под разными именами: метод slapd-config, RTC метод (настройка в реальном времени) или cn=config метод. Вы все еще можете использовать традиционный метод плоского файла (slapd.conf), но это не рекомендуется; данная функциональность в конечном счете будет убрана.

Ubuntu теперь использует метод slapd-config для настройки slapd и данное руководство это отражает.

Во время установки у вас будет запрос на информацию об администраторе. Это LDAP данные для rootDN вашего экземпляра базы данных. По умолчанию этот пользовательский DN cn=admin,dc=example,dc=com. Также по умолчанию не создается административного пользователя для базы данных slapd-config и вы, следовательно, будете вынуждены использовать внешнюю авторизацию LDAP для доступа к ней. Мы рассмотрим как это делается позднее.

Некоторые классические схемы (cosine, nis, inetorgperson) выпускаются теперь для slapd. Это также включает базовую (core) схему, которая предполагается для любой рабочей схемы.

Проверка после установки

Процесс установки создаст 2 DIT. Один для slapd-config и один для ваших данных (dc=example,dc=com). Давайте взглянем:

  • Здесь показано как выглядит дерево (DIT) базы данных slapd-config. Напомним, что эта база основана на LDIF и находится в /etc/ldap/slapd.d:

        /etc/ldap/slapd.d/

    	├── cn=config
    	│   ├── cn=module{0}.ldif
    	│   ├── cn=schema
    	│   │   ├── cn={0}core.ldif
    	│   │   ├── cn={1}cosine.ldif
    	│   │   ├── cn={2}nis.ldif
    	│   │   └── cn={3}inetorgperson.ldif
    	│   ├── cn=schema.ldif
    	│   ├── olcBackend={0}hdb.ldif
    	│   ├── olcDatabase={0}config.ldif
    	│   ├── olcDatabase={-1}frontend.ldif
    	│   └── olcDatabase={1}hdb.ldif
    	└── cn=config.ldif

Не редактируйте базу slapd-config напрямую. Вносите изменения через протокол LDAP (утилитами).

  • Здесь показано как выглядит дерево slapd-config через LDAP протокол:

sudo ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b cn=config dn
dn: cn=config
dn: cn=module{0},cn=config
dn: cn=schema,cn=config
dn: cn={0}core,cn=schema,cn=config
dn: cn={1}cosine,cn=schema,cn=config
dn: cn={2}nis,cn=schema,cn=config
dn: cn={3}inetorgperson,cn=schema,cn=config
dn: olcBackend={0}hdb,cn=config
dn: olcDatabase={-1}frontend,cn=config
dn: olcDatabase={0}config,cn=config
dn: olcDatabase={1}hdb,cn=config

Объяснение по записям:

  1. cn=config: глобальные настройки

  2. cn=module{0},cn=config: динамически загружаемый модуль

  3. cn=schema,cn=config: содержит жестко запрограммированную схему системного уровня

  4. cn={0}core,cn=schema,cn=config: жестко запрограммированная схема ядра (core)

  5. cn={1}cosine,cn=schema,cn=config: схема cosine

  6. cn={2}nis,cn=schema,cn=config: схема nis

  7. cn={3}inetorgperson,cn=schema,cn=config: схема inetorgperson

  8. olcBackend={0}hdb,cn=config: тип хранилища 'hdb' заднего плана

  9. olcDatabase={-1}frontend,cn=config: база переднего плана, настройка по умолчанию для других баз данных

  10. olcDatabase={0}config,cn=config: конфигурационная база slapd (cn=config)

  11. olcDatabase={1}hdb,cn=config: экземпляр вашей базы данных (dc=examle,dc=com)

  • А здесь показано как выглядит дерево dc=example,dc=com:

ldapsearch -x -LLL -H ldap:/// -b dc=example,dc=com dn
dn: dc=example,dc=com
dn: cn=admin,dc=example,dc=com

Объяснение по записям:

  1. dc=example,dc=com: базовый уровень вашего дерева (DIT)

  2. cn=admin,dc=example,dc=com: администратор (rootDN) данного дерева (заполняется в процессе установки пакета)

Изменение/заполнение вашей базы данных

Давайте введем некоторые данные в нашу базу. Мы добавим следующее:

  1. ноду с названием People (сохранять пользователей)

  2. ноду с названием Groups (сохранять группы)

  3. группу с названием miners

  4. пользователя с именем john

Создайте следующий LDIF файл и назовите его add_content.ldif:

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

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

dn: cn=miners,ou=Groups,dc=example,dc=com
objectClass: posixGroup
cn: miners
gidNumber: 5000

dn: uid=john,ou=People,dc=example,dc=com
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
uid: john
sn: Doe
givenName: John
cn: John Doe
displayName: John Doe
uidNumber: 10000
gidNumber: 5000
userPassword: johnldap
gecos: John Doe
loginShell: /bin/bash
homeDirectory: /home/john

Важно, чтобы значения uid и gid в вашем каталоге не совпадали с локальными значениями. Используйте диапазон больших чисел, начинающийся, например, с 5000. Устанавливая значения uid и gid высокими для ldap, вы сможете проще контролировать что могут делать локальные пользователи, а что ldap. Подробнее далее.

Добавляем контент:

ldapadd -x -D cn=admin,dc=example,dc=com -W -f add_content.ldif
Enter LDAP Password: ********
adding new entry "ou=People,dc=example,dc=com"
adding new entry "ou=Groups,dc=example,dc=com"
adding new entry "cn=miners,ou=Groups,dc=example,dc=com"
adding new entry "uid=john,ou=People,dc=example,dc=com"

Мы можем проверить, что информация добавлена правильно с помощью утилиты ldapsearch:

ldapsearch -x -LLL -b dc=example,dc=com 'uid=john' cn gidNumber
dn: uid=john,ou=People,dc=example,dc=com
cn: John Doe
gidNumber: 5000

Объяснения по параметрам:

  1. -x: "простое" связывание; не будет использоваться метод SASL по умолчанию

  2. -LLL: отключить вывод посторонней информации

  3. uid=john: "фильтр" для нахождения пользователя john

  4. cn gidNumber: запрос на вывод определенных атрибутов (по умолчанию выводятся все атрибуты)

Изменение базы данных настройки slapd

Дерево (DIT) slapd-config также может запрашиваться и изменяться. Здесь приведено несколько примеров.

  • Используйте ldapmodify для добавления индекса (атрибут DbIndex) для вашей {1}hdb,cn=config базы (dc=example,dc=com). Создайте файл с названием uid_index.ldif следующего содержания:

    dn: olcDatabase={1}hdb,cn=config
    add: olcDbIndex
    olcDbIndex: uid eq,pres,sub

Затем выполните команду:

    sudo ldapmodify -Q -Y EXTERNAL -H ldapi:/// -f uid_index.ldif
    modifying entry "olcDatabase={1}hdb,cn=config"

Вы можете подтвердить изменения следующим способом:

    sudo ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b \
    cn=config '(olcDatabase={1}hdb)' olcDbIndex

    dn: olcDatabase={1}hdb,cn=config
    olcDbIndex: objectClass eq
    olcDbIndex: uid eq,pres,sub
  • Давайте добавим схему. Это будет первый раз, когда потребуется конвертация в LDIF формат. Вы можете найти несконвертированные схемы в добавление к сконвертированным в каталоге /etc/ldap/schema.

  1. Удаление схемы из базы slapd-config - нетривиальная задача. Потренируйтесь добавлять схемы на тестовой системе.

  2. Перед добавлением любой схемы, вам следует проверить какие схемы уже установлены (показан вывод по умолчанию, для состояния "из коробки"):

        sudo ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b \
        cn=schema,cn=config dn
        dn: cn=schema,cn=config
        dn: cn={0}core,cn=schema,cn=config
        dn: cn={1}cosine,cn=schema,cn=config    In the following example we'll add the CORBA schema.

        dn: cn={2}nis,cn=schema,cn=config
        dn: cn={3}inetorgperson,cn=schema,cn=config

В следующем примере мы добавим схему CORBA.

  • Создайте конфигурационный файл преобразования schema_convert.conf, содержащий следующие строки:

        include /etc/ldap/schema/core.schema
        include /etc/ldap/schema/collective.schema
        include /etc/ldap/schema/corba.schema
        include /etc/ldap/schema/cosine.schema
        include /etc/ldap/schema/duaconf.schema
        include /etc/ldap/schema/dyngroup.schema
        include /etc/ldap/schema/inetorgperson.schema
        include /etc/ldap/schema/java.schema
        include /etc/ldap/schema/misc.schema
        include /etc/ldap/schema/nis.schema
        include /etc/ldap/schema/openldap.schema
        include /etc/ldap/schema/ppolicy.schema
        include /etc/ldap/schema/ldapns.schema
        include /etc/ldap/schema/pmi.schema
  • Создайте каталог назначения ldif_output.

  • Определите индекс схемы:

        slapcat -f schema_convert.conf -F ldif_output -n 0 | grep corba,cn=schema
        cn={1}corba,cn=schema,cn=config

Когда slapd вводит объекты с тем же родительским DN, он создает индекс для этого объекта. Индекс обрамляется скобками: {X}.

  • Используйте slapcat для выполнения преобразования:

        slapcat -f schema_convert.conf -F ldif_output -n0 -H \
        ldap:///cn={1}corba,cn=schema,cn=config -l cn=corba.ldif

Сконвертированная (преобразованная) схема теперь в cn=corba.ldif

  • Редактируйте cn=corba.ldif, по достижении следующих атрибутов:

        dn: cn=corba,cn=schema,cn=config
        ...
        cn: corba

Также удалите следующие строки в конце:

        structuralObjectClass: olcSchemaConfig
        entryUUID: 52109a02-66ab-1030-8be2-bbf166230478
        creatorsName: cn=config
        createTimestamp: 20110829165435Z
        entryCSN: 20110829165435.935248Z#000000#000#000000
        modifiersName: cn=config
        modifyTimestamp: 20110829165435Z

Значения ваших атрибутов могут быть другими.

  • Наконец, используйте ldapadd для добавления новой схемы к дереву slapd-config:

        sudo ldapadd -Q -Y EXTERNAL -H ldapi:/// -f cn\=corba.ldif
        adding new entry "cn=corba,cn=schema,cn=config"
  • Проверьте текущую загруженную схему:

        sudo ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b cn=schema,cn=config dn
        dn: cn=schema,cn=config
        dn: cn={0}core,cn=schema,cn=config
        dn: cn={1}cosine,cn=schema,cn=config
        dn: cn={2}nis,cn=schema,cn=config
        dn: cn={3}inetorgperson,cn=schema,cn=config
        dn: cn={4}corba,cn=schema,cn=config

Для аутентификации с помощью LDAP внешних приложений и клиентов, они должны быть специфически настроены. Обратитесь к соответствующей документации по поводу деталей.

Ведение журналов

Ведение журнала активности для slapd обязательно, когда осуществляется решение на базе OpenLDAP, поэтому его требуется включить вручную после установки приложения. Иначе только элементарные сообщения будут доступны в журналах. Ведение журналов, как и другие настройки slapd, подключаются через базу данных slapd-config.

OpenLDAP поставляется с несколькими подсистемами (уровнями) журналирования, каждая из которых включает подчиненную (дополнительную). Хороший вариант, который стоит попробовать - это stats. Страница руководства slapd-config содержит больше информации по иным подсистемам.

Создайте файл logging.ldif со следующим содержимым:

dn: cn=config
changetype: modify
add: olcLogLevel
olcLogLevel: stats

Производим изменения:

sudo ldapmodify -Q -Y EXTERNAL -H ldapi:/// -f logging.ldif

Это породит значительный объем записи в журнал и вы захотите уменьшить уровень детализации когда ваша система станет боевой. С таким уровнем детализации система журналирования вашего хоста (rsyslog) может отнимать значительное время процессора, а также пропускать сообщения:

rsyslogd-2177: imuxsock lost 228 messages from pid 2547 due to rate-limiting

Вы можете решить изменить настройки rsyslog. В файл /etc/rsyslog.conf поместите следующее:

# Disable rate limiting
# (default is 200 messages in 5 seconds; below we make the 5 become 0)
$SystemLogRateLimitInterval 0

А затем перезапустите сервис rsyslog:

sudo service rsyslog restart

Репликация

Сервис LDAP становится все более и более важным поскольку большинство сетевых систем начинают зависеть от него. В этом контексте стандартной практикой является встраивание избыточности (высокой доступности) в LDAP для защиты от опустошения, которое сделает сервер неработающим. Это достигается с помощью репликации LDAP.

Репликация доступна через механизм Syncrepl. Он позволят синхронизировать изменения используя модель Потребитель-Поставщик. Специфический вид репликации, который мы будем реализовывать в этом руководстве, является комбинацией следующих режимов: refreshAndPersist и delta-syncrepl. Это подразумевает что Потребитель передает измененные записи Поставщику, как только они появляются, но при этом посылаются только актуальные изменения, а не все записи.

Настройка Поставщика

Начнем с настройки Поставщика.

  • Создадим LDIF файл со следующим содержимым и назовем его provider_sync.ldif:

    # Add indexes to the frontend db.
    dn: olcDatabase={1}hdb,cn=config
    changetype: modify
    add: olcDbIndex
    olcDbIndex: entryCSN eq
    -
    add: olcDbIndex
    olcDbIndex: entryUUID eq

    #Load the syncprov and accesslog modules.
    dn: cn=module{0},cn=config
    changetype: modify
    add: olcModuleLoad
    olcModuleLoad: syncprov
    -
    add: olcModuleLoad
    olcModuleLoad: accesslog

    # Accesslog database definitions
    dn: olcDatabase={2}hdb,cn=config
    objectClass: olcDatabaseConfig
    objectClass: olcHdbConfig
    olcDatabase: {2}hdb
    olcDbDirectory: /var/lib/ldap/accesslog
    olcSuffix: cn=accesslog
    olcRootDN: cn=admin,dc=example,dc=com
    olcDbIndex: default eq
    olcDbIndex: entryCSN,objectClass,reqEnd,reqResult,reqStart

    # Accesslog db syncprov.
    dn: olcOverlay=syncprov,olcDatabase={2}hdb,cn=config
    changetype: add
    objectClass: olcOverlayConfig
    objectClass: olcSyncProvConfig
    olcOverlay: syncprov
    olcSpNoPresent: TRUE
    olcSpReloadHint: TRUE

    # syncrepl Provider for primary db
    dn: olcOverlay=syncprov,olcDatabase={1}hdb,cn=config
    changetype: add
    objectClass: olcOverlayConfig
    objectClass: olcSyncProvConfig
    olcOverlay: syncprov
    olcSpNoPresent: TRUE

    # accesslog overlay definitions for primary db
    dn: olcOverlay=accesslog,olcDatabase={1}hdb,cn=config
    objectClass: olcOverlayConfig
    objectClass: olcAccessLogConfig
    olcOverlay: accesslog
    olcAccessLogDB: cn=accesslog
    olcAccessLogOps: writes
    olcAccessLogSuccess: TRUE
    # scan the accesslog DB every day, and purge entries older than 7 days
    olcAccessLogPurge: 07+00:00 01+00:00

Замените rootDN в LDIF файле на соответствующий вашему каталогу.

  • Профиль apparmor для slapd нужно будет отрегулировать для расположения базы accesslog. Отредактируйте /etc/apparmor.d/local/usr.sbin.slapd, добавив следующее:

    /var/lib/ldap/accesslog/ r,
    /var/lib/ldap/accesslog/** rwk,

Создаем каталог, устанавливаем файл настроек базы данных и перегружаем профиль apparmor:

    sudo -u openldap mkdir /var/lib/ldap/accesslog
    sudo -u openldap cp /var/lib/ldap/DB_CONFIG /var/lib/ldap/accesslog
    sudo service apparmor reload
  • Добавляем новый контент и, поскольку изменили apparmor, перестартуем сервис:

    sudo ldapadd -Q -Y EXTERNAL -H ldapi:/// -f provider_sync.ldif
    sudo service slapd restart

Поставщик теперь настроен.

Настройка Потребителя

А теперь настроим Потребителя.

  • Установим программное обеспечение как указано в Установке. Убедитесь, что база slapd-config аналогична базе Поставщика. Особенно проверьте, что одинаковы схемы и суффикс базы.

  • Создайте LDIF файл со следующим содержимым и назовите его consumer_sync.ldif:

    dn: cn=module{0},cn=config
    changetype: modify
    add: olcModuleLoad
    olcModuleLoad: syncprov

    dn: olcDatabase={1}hdb,cn=config
    changetype: modify
    add: olcDbIndex
    olcDbIndex: entryUUID eq
    -
    add: olcSyncRepl
    olcSyncRepl: rid=0 provider=ldap://ldap01.example.com bindmethod=simple binddn="cn=admin,dc=example,dc=com" 
     credentials=secret searchbase="dc=example,dc=com" logbase="cn=accesslog" 
     logfilter="(&(objectClass=auditWriteObject)(reqResult=0))" schemachecking=on 
     type=refreshAndPersist retry="60 +" syncdata=accesslog
    -
    add: olcUpdateRef
    olcUpdateRef: ldap://ldap01.example.com

Убедитесь, что следующие атрибуты имеют корректные значения:

  1. provider (hostname сервера Поставщика - ldap01.example.com в этом примере - или IP адрес)

  2. binddn (DN администратора, которым вы пользуетесь)

  3. credentials (пароль для DN администратора, который вы используете)

  4. searchbase (суффикс базы, которую вы используете)

  5. olcUpdateRef (hostname сервера Поставщика или его IP адрес)

  6. rid (Replica ID, уникальное трехзначное число, идентифицирующее данную копию. Каждый Потребитель должен иметь минимум один rid)

  • Добавьте новый контент:

sudo ldapadd -Q -Y EXTERNAL -H ldapi:/// -f consumer_sync.ldif

Вы сделали это! Две базы (суффикс: dc=example,dc=com) будут теперь синхронизированы.

Проверка

Как только репликация стартует, вы можете отслеживать ее запустив:

ldapsearch -z1 -LLLQY EXTERNAL -H ldapi:/// -s base contextCSN

dn: dc=example,dc=com
contextCSN: 20120201193408.178454Z#000000#000#000000

как на Поставщике, так и на Потребителе. Как только вывод (20120201193408.178454Z#000000#000#000000 в примере выше) на обеих машинах совпадет, вы провели репликацию. Каждый раз, как происходят изменения на Поставщике, это значение будет изменяться и должно стать таким же на Поставщике.

Если ваше соединение медленное и/или ваша база LDAP велика, процесс приведения в соответствие contextCSN Потребителя и Поставщика может быть протяженным. Но, вы должны знать, что процесс запускается как только contextCSN Потребителя неизбежно увеличивается.

Если contextCSN Потребителя отсутствует или не совпадает со значением Поставщика, вы должны остановиться и понять причину проблемы перед тем как продолжить. Попробуйте проверить slapd (syslog - системный журнал) и файлы журналов авторизации Поставщика, чтобы увидеть удачны ли были запросы авторизации Потребителя и не возвращались ли ошибки в ответ на запросы данных (они будут видны как множество записей ldapsearch).

Чтобы проверить, что все работает, просто запросите на Потребителе DN из базы:

sudo ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b dc=example,dc=com dn

Вы должны увидеть пользователя 'john' и группу 'miners', также как ноды 'People' и 'Groups'.

Контроль доступа

Управление какой тип доступа (чтение, запись и пр.) пользователей должен быть предоставлен к ресурсам известен как контроль доступа. Сочетания подобных директив называются Списками контроля доступа (ACL).

Когда мы устанавливаем пакет slapd различные ACL устанавливаются автоматически. Мы рассмотрим некоторые важные следствия этих умолчаний и, занимаясь этим, мы поймем идею того, как работают ACL и как их настраивать.

Для получения эффективных ACL для запроса LDAP нам надо посмотреть на ACL записи запрашиваемой базы данных также как и на записи специального экземпляра базы данных переднего плана. По умолчанию используются ACL, полученные последним действием, в случае, если они не совпадают с правилами из предыдущего варианта. База данных переднего плана опрашивается во вторую очередь и применяется ACL по первому совпадению среди этих двух источников ACL. Следующие команды покажут соответственно ACL базы hdb ("dc=example,dc=com") и они же из базы переднего плана:

FIXME оставлен оригинал предыдущего абзаца, поскольку не уверен, что правильно понял смысл:

To get the effective ACL for an LDAP query we need to look at the ACL entries of the database being queried as well as those of the special frontend database instance. The ACLs belonging to the latter act as defaults in case those of the former do not match. The frontend database is the second to be consulted and the ACL to be applied is the first to match («first match wins») among these 2 ACL sources. The following commands will give, respectively, the ACLs of the hdb database («dc=example,dc=com») and those of the frontend database:

sudo ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b \
cn=config '(olcDatabase={1}hdb)' olcAccess

dn: olcDatabase={1}hdb,cn=config
olcAccess: {0}to attrs=userPassword,shadowLastChange by self write by anonymous
              auth by dn="cn=admin,dc=example,dc=com" write by * none
olcAccess: {1}to dn.base="" by * read
olcAccess: {2}to * by self write by dn="cn=admin,dc=example,dc=com" write by *
  read

rootDN всегда имеет полный доступ к своей базе данных. Добавление их к ACL обеспечивает полную конфигурацию, но при этом становится причиной снижения быстродействия slapd.

sudo ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b \
cn=config '(olcDatabase={-1}frontend)' olcAccess

dn: olcDatabase={-1}frontend,cn=config
olcAccess: {0}to * by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,
              cn=external,cn=auth manage by * break
olcAccess: {1}to dn.exact="" by * read
olcAccess: {2}to dn.base="cn=Subschema" by * read

Самый первый ACL очень важен:

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

Это может быть представлено по-другому для лучшего понимания:

to attrs=userPassword
	by self write
	by anonymous auth
	by dn="cn=admin,dc=example,dc=com" write
	by * none

to attrs=shadowLastChange
	by self write
	by anonymous auth
	by dn="cn=admin,dc=example,dc=com" write
	by * none

Этот составной ACL (их два) предписывает следующее:

  1. Анонимный 'auth' доступ обеспечивается к атрибуту userPassword для осуществления изначального соединения. Возможно потребуется counter-intuitively для 'by anonymous auth' даже когда анонимный доступ к DIT не требуется. Как только удаленное соединение установлено, требуется авторизация (см. следующий пункт).

  2. Должна пройти авторизация, поскольку все пользователи имеют доступ на чтение (вследствие 'by self write') к атрибуту userPassword.

  3. Атрибут userPassword не доступен для всех других пользователей за исключением rootDN, который имеет полный доступ.

  4. Для того чтобы пользователи могли менять собственные пароли, используя passwd или иные утилиты, атрибут shadowLastChange должен быть доступен как только пользователь авторизовался.

Поиск по этому DIT может быть проведен анонимно из-за 'by * read' в данном ACL:

to *
	by self write
	by dn="cn=admin,dc=example,dc=com" write
	by * read

Если это нежелательно, то вам потребуется изменить набор ACL. Для принуждения к авторизации в процессе связывающего (bind) запроса в качестве альтернативы (или в комбинации с измененным ACL) вам надо использовать директиву 'olcRequire: authc'.

Как указывалось ранее, никаких административных пользователей не создается для базы slapd-config. Однако существует идентификация SASL, которая обеспечивает полный к ней доступ. Она подобна суперпользователю для localhost (root/sudo). Вот она:

dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth

Следующая команда покажет ACL базы slapd-config:

sudo ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b \
cn=config '(olcDatabase={0}config)' olcAccess

dn: olcDatabase={0}config,cn=config
olcAccess: {0}to * by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,
              cn=external,cn=auth manage by * break

Поскольку это SASL идентификация, нам потребуется механизм SASL, когда запрашивается LDAP утилита, о которой идет речь и мы увидим это много раз в данном руководстве. Это внешний (EXTERNAL) механизм. Смотрите предыдущую команду в качестве примера. Обратите внимание:

  1. Вы должны использовать sudo для идентификации как root чтобы ACL сработали.

  2. Механизм EXTERNAL работает через IPC (доменные сокеты UNIX). Это означает , что вы должны использовать ldapi формат адресации (URI).

Короткий путь для получения всех ACL выглядит следующим образом:

sudo ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b \
cn=config '(olcAccess=*)' olcAccess olcSuffix

Есть еще много что сказать по контролю доступа. Смотрите страницу руководства по slapd.access.

TLS

Когда происходит аутентификация на OpenLDAP сервере, лучше всего это делать используя зашифрованную сессию. Это может быть достигнуто использованием транспортного уровня шифрования (TLS).

Здесь мы организуем свой собственный Центр сертификатов (Certificate Authority - CA) и затем создадим и подпишем сертификат нашего LDAP сервера от имени этого CA. Поскольку slapd скомпилирован с использованием библиотеки gnutls, мы будем использовать для выполнения этих задач утилиту certtool.

  • Устанавливаем пакеты gnutls-bin и ssl-cert:

sudo apt-get install gnutls-bin ssl-cert
  • Создаем секретный ключ Центра сертификатов:

sudo sh -c "certtool --generate-privkey > /etc/ssl/private/cakey.pem"
  • Создаем временный файл /etc/ssl/ca.info для определения CA:

    cn = Example Company
    ca
    cert_signing_key
  • Создаем самоподписанный сертификат центра:

sudo certtool --generate-self-signed \
    --load-privkey /etc/ssl/private/cakey.pem \ 
    --template /etc/ssl/ca.info \
    --outfile /etc/ssl/certs/cacert.pem
  • Создаем секретный ключ для сервера:

sudo certtool --generate-privkey \
    --bits 1024 \
    --outfile /etc/ssl/private/ldap01_slapd_key.pem

Замените ldap01 в имени файла на имя вашего сервера (hostname). Имена сертификата и ключа для узла и сервиса, которые будут их использовать, помогут сохранять ясность понимания.

  • Создаем информационный файл /etc/ssl/ldap01.info, содержащий следующее:

    organization = Example Company
    cn = ldap01.example.com
    tls_www_server
    encryption_key
    signing_key
    expiration_days = 3650

Данный сертификат будет действителен 10 лет (3650 дней). Вы можете выбрать другое значение.

  • Создаем серверный сертификат:

sudo certtool --generate-certificate \
    --load-privkey /etc/ssl/private/ldap01_slapd_key.pem \
    --load-ca-certificate /etc/ssl/certs/cacert.pem \
    --load-ca-privkey /etc/ssl/private/cakey.pem \
    --template /etc/ssl/ldap01.info \
    --outfile /etc/ssl/certs/ldap01_slapd_cert.pem

Создайте файл certinfo.ldif со следующим содержимым (подставляйте свои значения, наш пример предполагает использование https://www.cacert.org):

dn: cn=config
add: olcTLSCACertificateFile
olcTLSCACertificateFile: /etc/ssl/certs/cacert.pem
-
add: olcTLSCertificateFile
olcTLSCertificateFile: /etc/ssl/certs/ldap01_slapd_cert.pem
-
add: olcTLSCertificateKeyFile
olcTLSCertificateKeyFile: /etc/ssl/private/ldap01_slapd_key.pem

Используйте команду ldapmodify, чтобы сказать slapd о работе нашего TLS через базу данных slapd-config:

sudo ldapmodify -Y EXTERNAL -H ldapi:/// -f /etc/ssl/certinfo.ldif

Вопреки распространенному мнению, вам не обязательно указывать ldaps:// в /etc/default/slapd чтобы использовать шифрование. Вам достаточно указать:

SLAPD_SERVICES="ldap:/// ldapi:///"

LDAP поверх TLS/SSL (ldaps://) осуждается в пользу StartTLS. Последний опирается на существующую LDAP сессию (прослушивание TCP порта 389), защищенную TLS/SSL в то время как LDAPS, подобно HTTPS, является другим защищенным-с-самого-начала протоколом, который работает через TCP порт 636.

Сужаем права на владение и доступ:

sudo adduser openldap ssl-cert
sudo chgrp ssl-cert /etc/ssl/private/ldap01_slapd_key.pem
sudo chmod g+r /etc/ssl/private/ldap01_slapd_key.pem
sudo chmod o-r /etc/ssl/private/ldap01_slapd_key.pem

Перегружаем OpenLDAP:

sudo service slapd restart

Проверьте ваши системные журналы (/var/log/syslog) чтобы убедиться что сервер запустился правильно.

Репликация и TLS

Если вы настроили репликацию между серверами, существует общая практика шифровать (StartTLS) трафик репликации для исключения прослушивания. Лучше всего использовать шифрование с аутентификацией как мы делали выше. В этой секции мы будем основываться на проделанной работе по TLS-аутентификации.

Здесь предполагается, что вы настроили репликацию между Поставщиком и Провайдером в соответствии с секцией Репликация и настроили TLS для аутентификации на Поставщике следуя инструкциям секции TLS.

Как утверждалось ранее, цель (для нас) репликации - это высокая доступность сервиса LDAP. Поскольку мы имеем TLS для аутентификации на Поставщике, мы нуждаемся в этом и на Потребителе. Однако в дополнение к этому мы хотим зашифровать трафик репликации. Что остается сделать, так это создать ключ и сертификат для Потребителя и затем провести соответствующую настройку. Мы создадим ключ и сертификат на Поставщике для предотвращения создания другого Центра сертификатов, а затем перенесем необходимые данные на Потребителя.

  • На Поставщике:

Создаем промежуточный каталог (который будет использоваться для переноса) и затем секретный ключ Потребителя:

    mkdir ldap02-ssl
    cd ldap02-ssl
    sudo certtool --generate-privkey \
    --bits 1024 \
    --outfile ldap02_slapd_key.pem

Создаем информационный файл ldap02.info для сервера Потребителя; подставляйте свои соответствующие значения:

    organization = Example Company
    cn = ldap02.example.com
    tls_www_server
    encryption_key
    signing_key
    expiration_days = 3650

Создаем сертификат Потребителя:

    sudo certtool --generate-certificate \
    --load-privkey ldap02_slapd_key.pem \
    --load-ca-certificate /etc/ssl/certs/cacert.pem \
    --load-ca-privkey /etc/ssl/private/cakey.pem \
    --template ldap02.info \
    --outfile ldap02_slapd_cert.pem

Получаем копию сертификата CA:

cp /etc/ssl/certs/cacert.pem .

Все готово. Теперь переносим каталог ldap02-ssl на сервер Потребителя. Здесь мы использовали scp (данные изменяем соответственно):

    cd ..
    scp -r ldap02-ssl user@consumer:
  • На Потребителе:

Настраиваем TLS аутентификацию:

    sudo apt-get install ssl-cert
    sudo adduser openldap ssl-cert
    sudo cp ldap02_slapd_cert.pem cacert.pem /etc/ssl/certs
    sudo cp ldap02_slapd_key.pem /etc/ssl/private
    sudo chgrp ssl-cert /etc/ssl/private/ldap02_slapd_key.pem
    sudo chmod g+r /etc/ssl/private/ldap02_slapd_key.pem
    sudo chmod o-r /etc/ssl/private/ldap02_slapd_key.pem

Создаем файл /etc/ssl/certinfo.ldif со следующим содержимым (исправляйте соответственно):

    dn: cn=config
    add: olcTLSCACertificateFile
    olcTLSCACertificateFile: /etc/ssl/certs/cacert.pem
    -
    add: olcTLSCertificateFile
    olcTLSCertificateFile: /etc/ssl/certs/ldap02_slapd_cert.pem
    -
    add: olcTLSCertificateKeyFile
    olcTLSCertificateKeyFile: /etc/ssl/private/ldap02_slapd_key.pem

Настраиваем базу slapd-config:

sudo ldapmodify -Y EXTERNAL -H ldapi:/// -f certinfo.ldif

Настраиваем /etc/default/slapd как на Поставщике (SLAPD_SERVICES).

  • На Потребителе:

Настраиваем TLS для репликации на стороне Потребителя. Изменяем существующий атрибут olcSyncrepl присоединяя некоторые TLS опции. Делая это, мы увидим в первый раз как изменять значения атрибутов.

Создаем файл consumer_sync_tls.ldif со следующим содержимым:

    dn: olcDatabase={1}hdb,cn=config
    replace: olcSyncRepl
    olcSyncRepl: rid=0 provider=ldap://ldap01.example.com bindmethod=simple
     binddn="cn=admin,dc=example,dc=com" credentials=secret searchbase="dc=example,dc=com"
     logbase="cn=accesslog" logfilter="(&(objectClass=auditWriteObject)(reqResult=0))"
     schemachecking=on type=refreshAndPersist retry="60 +" syncdata=accesslog
     starttls=critical tls_reqcert=demand

Дополнительные опции определяют, соответственно, что Потребитель должен использовать StartTLS и что CA сертификат требуется для идентификации Поставщика. Также обратите внимание на LDIF синтаксис для изменения значений атрибута ('replace').

Применяем эти изменения:

sudo ldapmodify -Y EXTERNAL -H ldapi:/// -f consumer_sync_tls.ldif

И перестартуем slapd:

sudo service slapd restart
  • На Постащике:

Проверяем, что TLS сессия устанавливается. В /var/log/syslog, предполагая что вы настроили уровень журналирования 'conns', вы сможете увидеть подобные записи:

    slapd[3620]: conn=1047 fd=20 ACCEPT from IP=10.153.107.229:57922 (IP=0.0.0.0:389)
    slapd[3620]: conn=1047 op=0 EXT oid=1.3.6.1.4.1.1466.20037
    slapd[3620]: conn=1047 op=0 STARTTLS
    slapd[3620]: conn=1047 op=0 RESULT oid= err=0 text=
    slapd[3620]: conn=1047 fd=20 TLS established tls_ssf=128 ssf=128
    slapd[3620]: conn=1047 op=1 BIND dn="cn=admin,dc=example,dc=com" method=128
    slapd[3620]: conn=1047 op=1 BIND dn="cn=admin,dc=example,dc=com" mech=SIMPLE ssf=0
    slapd[3620]: conn=1047 op=1 RESULT tag=97 err=0 text

Установление подлинности через LDAP

Поскольку вы имеете работающий LDAP сервер, вам потребуется установить библиотеки на клиенте, которые будут знать как и когда к нему (серверу) подсоединяться. На Ubuntu это традиционно производится установкой пакета libnss-ldap. Этот пакет добавит другие инструменты, которые будут помогать вам на шаге настройки. Теперь установим этот пакет:

sudo apt-get install libnss-ldap

У вас будут запрошены подробности по вашему LDAP серверу. Если вы сделаете ошибку, вы можете попробовать снова используя:

sudo dpkg-reconfigure ldap-auth-config

Результат диалога можно увидеть в /etc/ldap.conf. Если ваш сервер требует опции, недоступные в меню, редактируйте этот файл самостоятельно.

Теперь настраиваем LDAP профиль для NSS:

sudo auth-client-config -t nss -p lac_ldap

Настраиваем систему на использование LDAP для аутентификации:

sudo pam-auth-update

Из меню, выберите LDAP и любые другие механизмы аутентификации, которые вам требуются.

Теперь вы имеете возможность входить в систему, используя учетные записи на основе LDAP.

Клиентам LDAP потребуются ссылки на несколько серверов, если используется репликация. В /etc/ldap.conf вам надо иметь что-то похожее:

uri ldap://ldap01.example.com ldap://ldap02.example.com

Запросы имеют таймаут и будет попытка обратиться к Потребителю (ldap02), если Поставщик (ldap01) станет недоступным.

Если вы собираетесь использовать LDAP для хранения пользователей SAMBA, вам потребуется настроить SAMBA сервер на использование LDAP. Смотрите Samba и LDAP для подробностей.

Альтернативой пакету libnss-ldap является пакет libnss-ldapd. Однако он добавит в систему пакет nscd, который, возможно, нежелателен. Просто впоследствии удалите его.

Управление пользователями и группами

Пакет ldap-utils поставляется с достаточным количеством утилит для управления каталогами, но необходимость использовать длинные строки с опциями делает их применение обременительным. Пакет ldapscripts содержит оберточные сценарии (wrapper scripts) для этих утилит, которые некоторые находят более удобными в использовании.

Устанавливаем пакет:

sudo apt-get install ldapscripts

Затем редактируем файл /etc/ldapscripts/ldapscripts.conf для получения нечто похожего на следующее:

SERVER=localhost
BINDDN='cn=admin,dc=example,dc=com'
BINDPWDFILE="/etc/ldapscripts/ldapscripts.passwd"
SUFFIX='dc=example,dc=com'
GSUFFIX='ou=Groups'
USUFFIX='ou=People'
MSUFFIX='ou=Computers'
GIDSTART=10000
UIDSTART=10000
MIDSTART=10000

Теперь создаем файл ldapscripts.passwd чтобы разрешить rootDN доступ к каталогу:

sudo sh -c "echo -n 'secret' > /etc/ldapscripts/ldapscripts.passwd"
sudo chmod 400 /etc/ldapscripts/ldapscripts.passwd

Замените "secret" на действующий пароль для пользователя rootDN вашей базы.

Сценарии теперь готовы помогать в управлении вашим каталогом. Здесь несколько примеров как их использовать:

  • Создать нового пользователя:

sudo ldapadduser george example

Это создаст пользователя с uid george и установит gid example в качестве первичной пользовательской группы.

  • Изменить пароль пользователя:

sudo ldapsetpasswd george
Changing password for user uid=george,ou=People,dc=example,dc=com
New Password:
New Password (verify):
  • Удалить пользователя:

sudo ldapdeleteuser george
  • Добавить группу:

sudo ldapaddgroup qa
  • Удалить группу:

sudo ldapdeletegroup qa
  • Добавить пользователя к группе:

sudo ldapaddusertogroup george qa

Вы теперь можете увидеть атрибут memberUid для группы qa со значением для george.

  • Удалить пользователя из группы:

sudo ldapdeleteuserfromgroup george qa

Атрибут memberUid теперь будет удален из группы qa.

  • Сценарий ldapmodifyuser позволяет вам добавлять, удалять или заменять пользовательские атрибуты. Сценарий исползует тот же синтаксис, что и утилита ldapmodify. Например:

    sudo ldapmodifyuser george
    # About to modify the following entry :
    dn: uid=george,ou=People,dc=example,dc=com
    objectClass: account
    objectClass: posixAccount
    cn: george
    uid: george
    uidNumber: 1001
    gidNumber: 1001
    homeDirectory: /home/george
    loginShell: /bin/bash
    gecos: george
    description: User account
    userPassword:: e1NTSEF9eXFsTFcyWlhwWkF1eGUybVdFWHZKRzJVMjFTSG9vcHk=

    # Enter your modifications here, end with CTRL-D.
    dn: uid=george,ou=People,dc=example,dc=com
    replace: gecos
    gecos: George Carlin

Поле имени пользователя (gecos) теперь "George Carlin".

  • Приятной особенностью ldapscripts является система шаблонов. Шаблоны позволяют вам настраивать атрибуты пользователей, групп и компьютерных объектов. Например, чтобы разрешить шаблон пользователей, отредактируйте /etc/ldapscripts/ldapscripts.conf, изменив:

UTEMPLATE="/etc/ldapscripts/ldapadduser.template"

В каталоге /etc/ldapscripts находятся шаблоны sample. Скопируйте или переименуйте файл ldapadduser.template.sample в /etc/ldapscripts/ldapadduser.template:

sudo cp /usr/share/doc/ldapscripts/examples/ldapadduser.template.sample \
 /etc/ldapscripts/ldapadduser.template

Отредактируйте новый шаблон для добавления желаемых атрибутов. Следующее создаст новых пользователей с objectClass inetOrgPerson:

    dn: uid=<user>,<usuffix>,<suffix>
    objectClass: inetOrgPerson
    objectClass: posixAccount
    cn: <user>
    sn: <ask>
    uid: <user>
    uidNumber: <uid>
    gidNumber: <gid>
    homeDirectory: <home>
    loginShell: <shell>
    gecos: <user>
    description: User account
    title: Employee

Отметьте опцию <ask>, использованную для атрибута sn. Это создает запрос при использовании ldapadduser для его значения.

Есть утилиты из пакета, которые здесь не рассматривались. Вот их полный список:

ldaprenamemachine
ldapadduser
ldapdeleteuserfromgroup
ldapfinger
ldapid
ldapgid
ldapmodifyuser
ldaprenameuser
lsldap
ldapaddusertogroup
ldapsetpasswd
ldapinit
ldapaddgroup
ldapdeletegroup
ldapmodifygroup
ldapdeletemachine
ldaprenamegroup
ldapaddmachine
ldapmodifymachine
ldapsetprimarygroup
ldapdeleteuser

Резервное копирование и восстановление

Теперь у нас ldap работает именно так, как нам хотелось и настало время убедиться, что мы можем сохранить всю нашу работу и восстановить ее при необходимости.

Что нам требуется, это способ сделать резервные копии для базы данных ldap, специфичные для данных баз заднего (cn=config) и переднего плана (dc=example,dc=com). Если мы собираемся сохранить эти базы, скажем, в /export/backup, мы можем использовать slapcat как показано в следующем сценарии с именем /usr/local/bin/ldapbackup:

#!/bin/bash

BACKUP_PATH=/export/backup
SLAPCAT=/usr/sbin/slapcat

nice ${SLAPCAT} -n 0 > ${BACKUP_PATH}/config.ldif
nice ${SLAPCAT} -n 1 > ${BACKUP_PATH}/example.com.ldif
nice ${SLAPCAT} -n 2 > ${BACKUP_PATH}/access.ldif
chmod 640 ${BACKUP_PATH}/*.ldif

Это несжатые текстовые файлы, содержащие все данные из вашей ldap базы, включая расположение дерева, имена пользователей и каждый пароль. Поэтому вы можете решить сделать /export/backup шифрованным разделом и даже иметь сценарии шифрования этих файлов сразу после создания. В идеале вы можете сделать и то и другое, но это зависит от ваших требований безопасности.

Затем имеет смысл создать сценарии cron для запуска этой программы настолько часто, насколько вам будет комфортно. Для большинства достаточно одного раза в день. Для некоторых требуется чаще. Здесь пример сценария cron, названного /etc/cron.d/ldapbackup, который срабатывает каждую ночь в 22:45:

MAILTO=backup-emails@domain.com
45 22 * * *  root    /usr/local/bin/ldapbackup

Теперь файлы созданы и они могут быть скопированы на резервный сервер.

Предположим мы сделали переустановку ldap; процесс восстановления будет подобен следующему:

sudo service slapd stop
sudo mkdir /var/lib/ldap/accesslog
sudo slapadd -F /etc/ldap/slapd.d -n 0 -l /export/backup/config.ldif
sudo slapadd -F /etc/ldap/slapd.d -n 1 -l /export/backup/domain.com.ldif
sudo slapadd -F /etc/ldap/slapd.d -n 2 -l /export/backup/access.ldif
sudo chown -R openldap:openldap /etc/ldap/slapd.d/
sudo chown -R openldap:openldap /var/lib/ldap/
sudo service slapd start

Ссылки

  1. Первый ресурс это актуальная документация: www.openldap.org.
  2. Существует много страниц руководств пакета slapd. Здесь наиболее важные, особенно в плане рассматриваемых в этом руководстве материалов:
  3. Другие руководства:
  4. LDAP for Rocket Scientists от Zytrax; руководство менее педантичное, но содержащее всесторонне рассмотренный LDAP.
  5. OpenLDAP wiki страница сообщества Ubuntu имеет коллекцию заметок.
  6. LDAP System Administration от O'Reilly (текст, 2003)
  7. Mastering OpenLDAP от Packt (текст, 2007)