LXF104:Hardcore Linux

Материал из Linuxformat.

Перейти к: навигация, поиск

Содержание

LDAP: Защитим вход в Dovecot

Позволять кому попало использовать наш почтовый сервер без аутентификации пользователя – сущее безумие. Д-р Крис Браун наведет порядок с помощью LDAP…

Сегодняшнее утреннее чтение начнем с Книги Тукса, главы пятой, с самого первого стиха.

  1. В начале был файл с паролями, и файл с паролями был Unix. Через него все пользователи могли получить доступ; и без него никто из входящих не мог пройти. И сисадмины сказали, что это хорошо.
  2. Но вот настала Великая Сеть, и возроптали сисадмины, говоря: «Файл с паролями свое отслужил, требует он дублирования данных и затрудняет масштабирование на большую сеть». Тогда Sun сказал: «Не бойтесь, ибо мы принесли вам Желтые Страницы, которые централизуют данные пользователей».
  3. Но затем явились четыре мудреца из Beetea и сказали: «Не смеете вы взять имя Желтые Страницы, оно наша собственность и наша торговая марка». И ответил им Sun: «Пускай то, что раньше звалось Желтыми Страницами, отныне зовется NIS». И сисадмины сказали, что это хорошо.
  4. Но прошло время, и снова разочаровались сисадмины, и возроптали они во второй раз: «Истинно, NIS имеет плоское пространство имен и не имеет контроля доступа».
  5. И снова сказал Sun: «Не бойтесь, ибо мы принесли вам NIS+, иерархическое пространство имен в нем и контроль доступа в избытке». Но сисадмины возроптали в третий раз, по своему неразумию.
  6. И создан был консорциум, и родил он спецификацию X500. И X500 родил DAP, DAP родил DIXIE, а DIXIE родил LDAP. И увидели сисадмины, что это хорошо. И это конец нашего утреннего чтения.

Истинно говорю вам, в этот день, на этом уроке мы создадим службу каталогов LDAP и используем ее для аутентификации в агенте доступа к почте POP/IMAP Dovecot.

Азбука LDAP

LDAP (облегченный протокол доступа к каталогам) – это служба каталогов, которую в принципе можно использовать для хранения любых данных, хотя на практике она чаще используется для хранения информации о пользователях, в частности, аутентификационных данных. Благодаря наличию открытой реализации (OpenLDAP) LDAP стал популярен в мире Linux как замена служб типа NIS или NIS+; в мире Windows она тоже хорошо известна – как основа Microsoft Active Directory.

Служба каталогов немного похожа на базу данных: обе могут хранить большие объемы информации и эффективно выполнять в ней поиск. Однако, служба каталогов оптимизирована для чтения (поиска); отношение времени записи к времени чтения обычно велико, и это не годится для ситуаций, когда требуется частое обновление данных. Для справочника естественно, что чтение выполняется в 10000 раз чаще, чем запись. Реляционные базы данных более симметричны по скорости чтения и записи. Кроме того, каталоги обычно не поддерживают транзакции, откаты и реляционные операции, типа join, которые имеют важное значение для реляционных баз данных.

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

Вы можете использовать LDAP в разных целях: например, для аутентификации постоянных пользователей Linux; или для реализации отображений Postfix, таких как виртуальный почтовый ящик, рассмотренный на уроке прошлого месяца. На данном уроке мы используем LDAP для простой аутентификации пользователей в Dovecot.

Отдать должное мощи и гибкости LDAP в ограниченном пространстве статьи – примерно то же, что пытаться открыть мир классической музыки инопланетянину, промычав ему первые четыре ноты Пятой симфонии Бетховена; но мы постараемся.

Что в имени тебе моем?

Каталоги LDAP состоят из набора записей, упорядоченных в виде древовидной структуры. Каждая позиция в дереве идентифицируется так называемым «различимым именем» (distinguished name, dn). Например, dn может быть вида cn=cbrown,ou=users,dc=example,dc=com. Сравним его с другими видами синтаксиса: как имя файла в Linux, оно бы записалось в виде /com/example/users/cbrown, а «полное доменное имя» в DNS выглядело бы cbrown.users.example.com.

Каждая запись в справочнике содержит информацию в виде набора пар «атрибут:значение». Какие именно атрибуты присутствуют, определяется так называемым классом объекта записи. Например, наша запись cn=cbrown,ou=users,dc=example,dc=com является объектом класса posixAccount. Описание, какой атрибут ассоциируется с каким классом, называется схемой, и она задается в файлах схем. Например, здесь описание класса posixAccount берется из файла /etc/openldap/schema/nis.schema:

objectclass ( 1.3.6.1.1.1.2.0 NAME ‘posixAccount’
DESC ‘Abstraction of an account with POSIX attributes’
SUP top AUXILIARY
MUST ( cn $ uid $ uidNumber $ gidNumber $ homeDirectory )
MAY ( userPassword $ loginShell $ gecos $ description ) )

Здесь важно отметить имя класса, список требуемых атрибутов (условие MUST) и список необязательных атрибутов (условие MAY). Если вы знакомы с файлом паролей Linux, вы заметите сходство атрибутов в объекте posixAccount и полях в /etc/passwd. (Учтите, однако, что атрибут LDAP uid – это то, что мы назвали бы именем учетной записи, а атрибут uidNumber – как раз то, что мы называем UID!) В терминах объектно-ориентированного программирования вы можете представить запись в файле схемы как описание класса, а запись в каталоге – как экземпляр класса. Также возможно наследование класса от «вышестоящего» класса (в объектно-ориентированном программировании он называется родительским или базовым). Строка SUP top AUXILIARY в предыдущем примере говорит нам, что вышестоящий класс, находящийся на вершине иерархии классов – это сам posixAccount, который не наследуется ни от чего. Но зайти дальше в аналогиях с ООП не получится: записи LDAP содержат только данные. Никакого запускаемого кода (который ОО-программисты назвали бы методом) с объектом не ассоциируется.

LDAP как он есть

На стороне сервера услуги предоставляет демон slapd. В качестве своей базы данных он использует BDB (встраиваемая библиотека базы данных, первоначально разработанная UC Berkeley), а прелестно названный slurpd распространяет изменения на все копии справочника LDAP. На стороне клиента OpenLDAP предоставляет различные инструменты командной строки для манипулирования записями каталога, включающие ldapadd, добавляющий информацию в каталог, и ldapsearch, используемый для (угадали!) поиска по каталогу.

Для просмотра человеком записи каталога LDAP отображаются в текстовом формате, называемом LDIF (формат обмена данными LDAP). Это формально заданный синтаксис, в соответствии с которым записи каталога представляются «вне» LDAP. Например, LDIF используется для предварительного создания записи при вводе ее в каталог, переноса данных из одного справочника в другой или просмотра содержимого справочника. В развитие нашего примера, LDIF-представление пользователя cn=cbrown,ou=users,dc=example,dc=com будет выглядеть так:

dn: cn=cbrown,ou=users,dc=example,dc=com
objectclass: posixAccount
objectclass: Account
cn: cbrown
uid: cbrown
uidNumber: 555
gidNumber: 555
homeDirectory: /home/cbrown

Мы сфокусировали здесь внимание на типе объекта posixAccount, потому что он необходим нам для поддержки аутентификации.

Станция «Рабочая»

Хватит теории! Давайте же установим и сконфигурируем LDAP. Я использую сервер CentOS, как на прошлом уроке (CentOS – это эквивалент RHEL5), но все, что будет показано далее, легко применимо для других дистрибутивов RedHat или Fedora.

Мы будем использовать LDAP, который создан в Мичиганском университете (см. www.openldap.org). Установка его в CentOS проста:

# yum install openldap-clients openldap-servers

Рис. 1. Компоненты OpenLDAP.
Рис. 1. Компоненты OpenLDAP.

Рисунок 1 показывает основные компоненты OpenLDAP. Остальные компоненты клиента – модуль PAM LDAP (/lib/security/pam_ldap.so) и библиотека разрешения LDAP (/lib/libnss_ldap.so), поддерживающая хранение стандартных учетных записей Linux в LDAP; мы займемся ими в следующем месяце.

Для запуска службы LDAP необходимо кое-что изменить в файле конфигурации slapd (/etc/openldap/slapd.conf). Вот строки, которые я поменял:

 suffix = “dc=example,dc=com”
 rootdn = “cn=admin,dc=example,dc=com”
 rootpw = {SSHA}JM2o2+Z07QJ9CZxqD6CIL3aEe/zSzMmW

Первая задает «именованный контекст» нашей службы LDAP, то есть dn ее верхней записи. Здесь можно использовать все что угодно, но я основывался на доменном имени DNS (example.com) настраиваемой машины: это стандартное решение. Вторая строка задает dn для учетной записи администратора сервера LDAP (он имеет полный контроль над содержимым каталога – это аналог root для Linux), а третья строка задает хэшированный пароль для этой учетной записи. Хэшированный пароль я сгенерировал с помощью slappasswd:

# slappasswd
New password:
Re-enter new password:
{SSHA}JM2o2+Z07QJ9CZxqD6CIL3aEe/zSzMmW

а затем вырезал и вставил результат в файл. После этого я запустил службу:

# service ldap start

Рис. 2. Простая структура каталога LDAP для поддержки аутентификации.
Рис. 2. Простая структура каталога LDAP для поддержки аутентификации.

Далее нам надо заселить наш каталог записями, которые пригодятся для аутентификации. Чтобы сообразить, куда мы движемся, посмотрите на рисунок 2, там показана структура, которую нам надо создать.

Сперва нужно построить и добавить в справочник узлы верхнего уровня. Я решил создать учетные записи пользователей в узле ou=users,dc=example,dc=com. Слово ‘users’ не является ключевым, просто я взял такое имя. Я начал с создания файла LDIF, названного root.ldif:

# Build the root node
dn: dc=example,dc=com
dc: example
objectClass: dcObject
objectClass: organizationalUnit
ou: example dot com
# Build the users ou
dn: ou=users,dc=example,dc=com
ou: users
objectClass:
organizationalUnit

Затем я добавил этот узел в каталог с помощью команды:

# ldapadd -D “cn=admin,dc=example,dc=com” -x -W -f root.ldif

Теперь добавим учетную запись пользователя. Выполняется это сходным образом: создается файл LDIF, а затем используется ldapadd для его добавления. Вот файл (newuser.ldif), который я создал:

dn: cn=cbrown,ou=users,dc=
example,dc=com
objectclass: posixAccount
objectclass: Account
cn: cbrown
uid: cbrown
uidNumber: 555
gidNumber: 555
homeDirectory: /home/cbrown

Затем я добавил этот узел в каталог:

 # ldapadd -D “cn=admin,dc=example,dc=com” -x -W -f newuser.ldif

Так как записи LDAP нам понадобятся для аутентификации входа на сервер Dovecot, я должен задать еще и пароль для пользователя, как показано здесь:

 # ldappasswd -x -D “cn=admin,dc=example,dc=com” -W -S “cn=cbrown,ou=users,dc=example,dc=com”
 New password:
 Re-enter new password:
 Enter LDAP Password:
 Result: Success (0)

Теперь не мешает проверить, что пользователь был добавлен в каталог; давайте выполним поиск записи. Для этого можно употребить ldapsearch:

# ldapsearch -x -b “ou=users,dc=example,dc=com” ‘(cn=cbrown)’
# cbrown, users, example.com
dn: cn=cbrown,ou=users,dc=example,dc=com
objectClass: posixAccount
objectClass: account
cn: cbrown
uid: cbrown
uidNumber: 555
gidNumber: 555
homeDirectory: /home/cbrown
userPassword:: e1NTSEF9cCt2Sml1enpCSTdOZjJUSU1ZcEp0c
U5LTnQzVHhjZzg=
# search result
search: 2
result: 0 Success
# numResponses: 2
# numEntries: 1

Это упражнение следует проделать для других пользователей, но если у вас их много, есть смысл автоматизировать процесс с помощью скрипта.

Справочники создаются именно для поиска в них, поэтому стоит разобрать поиск LDAP более подробно. Команда ldapsearch немного похожа на SQL-запрос к реляционной базе данных. Попробуем обойтись без формального описания синтаксиса. Я придумал хороший пример: разбил команду на несколько строк и для удобства ссылок пронумеровал их. Первые шесть строк из представленных ниже – на самом деле одна команда (обратные слэши у них на конце указывают, что команда продолжается на следующей строке). Для запуска этой команды в терминале просто удалите номера и, естественно, слэши, набрав весь код в одну строку.

  1. # ldapsearch -h mail.example.com \
  2. -x -LLL -b “dc=example,dc=com” \
  3. -D cn=admin,dc=example,dc=com -W
  4. -s sub \
  5. (|(uid=*brown)(gidNumber<=100))’ \
  6. uid
  7. Enter LDAP Password:
  8. dn: cn=cbrown,ou=users,dc=example,dc=com
  9. uid: cbrown
Рис. 3. Просмотр справочника LDAP с помощью LAT. Снимок экрана показывает запись, добавленную нами для пользователя cbrown.
Рис. 3. Просмотр справочника LDAP с помощью LAT. Снимок экрана показывает запись, добавленную нами для пользователя cbrown.
Рис. 4. Выполнение поиска в LDAP при помощи LAT.
Рис. 4. Выполнение поиска в LDAP при помощи LAT.

Теперь давайте вникать:

  1. Флаг -h используется для указания хоста, где запущен сервер LDAP. По умолчанию считается, что это localhost.
  2. Аргумент -x велит команде использовать простой метод аутентификации (не SASL), -LLL снижает число комментариев и прочих лишних слов в выводе, а флаг -b определяет, где мы хотим начать поиск в дереве справочника. В нашем случае мы начинаем с вершины дерева.
  3. Флаг -D задает dn пользователя, под которым мы хотим зайти (это пользователь, определенный параметром rootdn в slapd.conf), а -W велит команде запрашивать пароль.
  4. Здесь говорится, что поиск должен захватывать все ветви указанной базы, так что в данном случае мы запускаем поиск по всему справочнику.
  5. Пример фильтра поиска. Он говорит «покажите мне записи, где имя пользователя заканчивается на ‘brown’ или ID группы меньше или равно 100». Фильтры поиска – самая трудная часть синтаксиса для правильного написания, но (в определенном смысле) и самая важная.
  6. Эта строка содержит список имен атрибутов, которые мы хотим отобразить (в нашем случае просто имя пользователя). Если список пуст, ldapsearch покажет все атрибуты.
  7. Далее мы запрашиваем пароль для входа LDAP.

Наконец, строки 8 и 9 показывают вывод поиска.

Осилим еще один пример?

  1. # ldapsearch -x \
  2. -b “ou=users,dc=example,dc=com” \
  3. -D cn=admin,dc=example,dc=com -W \
  4. -s base ‘(objectClass=*)

Рассмотрим строки 2 и 4. В строке 2 задан конкретный узел дерева справочника, откуда начнется поиск, а в строке 4 мы говорим LDAP не распространять поиск за пределы этого узла, а изучать только записи, заданные в строке 2. Фильтр поиска здесь фактически и не фильтр: он гласит «любая запись с атрибутом objectClass, независимо от значения», а это вообще все записи. Итак, этот поиск выводит на дисплей содержимое определенного узла дерева.

Если вы предпочли бы использовать графические инструменты для поиска в вашем справочнике LDAP или добавления учетной записи пользователя, обратите внимание на Lat (LDAP Administration Tool). Это одно из новоиспеченных приложений, написанное на C# с использованием Mono и GTK#, поэтому вам понадобятся установленные библиотеки Mono для его использования, но на моем клиенте с Ubuntu он установился и работал без каких-либо проблем. Рисунок 3 показывает этот инструмент в работе при обозревании иерархии LDAP, а на рисунке 4 показан пример поиска по UID 555.

Аутентификация Dovecot

Давайте закруглимся, применив каталог LDAP к полезному делу. Читатели предыдущего номера могут помнить, что мы оставили нашего героя (почтовый сервер Dovecot) нуждающимся в аутентификации учетных записей POP3 базы данных пользователей, независимых от учетных записей пользователей в Linux.

Оказывается, Dovecot может использовать LDAP для аутентификации двумя способами: он может войти в LDAP с именем пользователя ‘rootdn’ и паролем ‘rootpw’, затем посмотреть имя пользователя и хэшированный пароль пользователя, который пытается аутентифицироваться, а может просто попробовать подключиться к серверу LDAP с именем и паролем того пользователя, кто пытается войти, и посмотреть, успешна ли попытка. Вход в LDAP известен как ‘связывание’, и эта техника называется аутентификационной связью. Этот метод мы и будем использовать.

Настройка Dovecot на использование LDAP для аутентификационной связи требует изменений в файле /etc/Dovecot.conf. Вот строки, которые я менял:

auth_verbose = yes
auth_debug = yes
passdb ldap {
args = /etc/dovecot-ldap.conf
}
userdb ldap {
args = /etc/dovecot-ldap.conf
}

Первые две строки включают вывод отладочных сообщений. На рабочем сервере они вам не понадобятся, но мне файл журнала (/var/log/maillog) очень помог при отладке конфигурации Dovecot. Две остальные строфы файла указывают, что мы будем использовать LDAP и как базу данных паролей, и как базу данных пользователей, и задают место размещения файла конфигурации LDAP для Dovecot.

Дико извиняюсь, но есть еще один файл конфигурации! Для его создания я начал с копирования примера конфигурации LDAP из дистрибутива Dovecot на место:

 # cp /usr/share/doc/dovecot-1.0/examples/dovecot-ldap.conf /etc

Затем я сделал следующие изменения в /etc/Dovecot-ldap.conf (номера строк опять-таки нужны только для ссылок на них в тексте):

  1. hosts = localhost
  2. dn = cn=admin,dc=example,dc=com
  3. dnpass = adminpw
  4. auth_bind = yes
  5. auth_bind_userdn = cn=%u,ou=users,dc=example,dc=com
  6. base = ou=users,dc=example,dc=com

Строка 1 задает имя сервера, на котором запущен LDAP. Строка 2 определяет dn учетной записи, которое Dovecot будет использовать для входа в LDAP, а строка 3 задает пароль для этой учетной записи. (Вообще-то было бы лучше не использовать для этого учетную запись с полными правами rootdn, а создать особую учетную запись для Dovecot). Строка 4 говорит, что будет использоваться аутентификационная связь, а строка 5 задает dn пользователя, которого мы пробуем аутентифицировать как такового (над этим мне пришлось поломать голову!). В файле конфигурации Dovecot, %u ссылается на имя пользователя, которое использует MUA (почтовый агент) пользователя, чтобы войти. Строка 6 определяет узел в дереве справочника LDAP, под которым находятся учетные записи пользователей.

Угнездив на месте эти строки, я смог подсоединиться к службе POP3 Dovecot с учетной записью cbrown и забрать почту.

Если у вас что-то не заработало, загляните в файл журнала, обычно /var/log/maillog. Сообщения, оставляемые Dovecot, очень подробны и говорят сами за себя. LXF


Что еще почитать? (врезка)

  1. По LDAP существует множество книг. Самыми полезными мне показались две: LDAP System Administration by Gerald Carter (O’Reilly, 1-56592-491-6), и Understanding and Deploying LDAP Directory Services by Howes, Smith and Good (Addison Wesley, 0672323168). Последняя более академическая (и тяжелая!)
  2. Официальная документация Dovecot доступна по адресу http://wiki.dovecot.org. В частности, статья http://wiki.dovecot.org/AuthDatabase/LDAP показывает, как сделать аутентификацию LDAP в Dovecot. Кроме того, slapd.conf, ldap.conf и все инструменты командной строки имеют прекрасные man-страницы.
  3. Основную информацию по сборке почтового сервера можно найти по адресам http://freshrpms.net/docs/mail-server и http://wanderingbarque.com/howtos/mailserver/mailserver.html. (Это очень подробное пошаговое руководство, написанное Питером Лэйси [Peter Lacey]; оно охватывает интеграцию Postfix, Dovecot, OpenLDAP, Jamm, Cyrus-SASL и SquirrelMail, и основано на RHEL 3).
Личные инструменты
  • Купить электронную версию
  • Подписаться на бумажную версию