Postfix может использовать каталог LDAP в качестве источника для любых своих поисков: aliases(5)
, virtual(5)
, canonical(5)
и других. Это позволяет вам хранить информацию для своей почтовой службы в реплицируемой сетевой базе данных с детализированным контролем доступа. За счёт отказа от хранения её локально на почтовом сервере администратор получает возможность поддерживать его откуда угодно, а пользователи могут контролировать всё, что вы посчитаете уместным. У вас может быть несколько почтовых серверов, использующих одинаковую информацию, без хлопот и задержек, связанных с необходимостью копирования её на каждый из них.
Темы, раскрываемые в этом документе:
Данная инструкция подразумевает, что вы собираете Postfix из исходных кодов как описано в документе INSTALL
. Если вы собираете Postfix из пакета исходных кодов какого-то конкретного поставщика, то процесс может несколько отличаться.
Примечание 1: Postfix больше не поддерживает интерфейс LDAP версии 1.
Примечание 2: для использования LDAP со сборкой Postfix от Debian GNU/Linux вам нужно будет только установить пакет postfix-ldap и всё. Перекомпилировать Postfix не требуется.
Библиотеки LDAP и подключаемые файлы должны быть установлены в каком-либо месте в вашей системе, и вы должны соответствующим образом сконфигурировать make-файлы Postfix.
Например, чтобы собрать библиотеки OpenLDAP для использования с Postfix (только клиентский код LDAP), можно использовать следующую команду:
% ./configure --without-kerberos --without-cyrus-sasl --without-tls \ --without-threads --disable-slapd --disable-slurpd \ --disable-debug --disable-shared
Если вы используете библиотеки из дистрибутива UM (http://www.umich.edu/~dirsvcs/ldap/ldap.html) или OpenLDAP (http://www.openldap.org), что-то наподобие таких команд, выполняемых на верхнем уровне дерева исходных кодов Postfix, должно работать:
% make tidy % make makefiles CCARGS="-I/usr/local/include -DHAS_LDAP" \ AUXLIBS_LDAP="-L/usr/local/lib -lldap -L/usr/local/lib -llber"
Версии Postfix до 3.0 используют переменную AUXLIBS
вместо AUXLIBS_LDAP
. В Postfix 3.0 и более новых версиях старая переменная AUXLIBS
по-прежнему поддерживает создание статически загружаемого клиента базы данных LDAP, но лишь новая переменная AUXLIBS_LDAP
поддерживает создание как динамически, так и статически загружаемого клиента базы данных LDAP.
Отказ от использования переменной
AUXLIBS_LDAP
приведёт к тому, что цель динамической загрузки клиента базы данных не будет достигнута: каждый исполняемый файл Postfix будет иметь зависимости от библиотеки базы данных LDAP, а именно этого предполагается избежать при динамической загрузке клиента базы данных.
В Solaris 2.x вам, возможно, понадобится указать информацию о компоновке во время исполнения, иначе ld.so не найдет некоторые разделяемые библиотеки:
% make tidy % make makefiles CCARGS="-I/usr/local/include -DHAS_LDAP" \ AUXLIBS_LDAP="-L/usr/local/lib -R/usr/local/lib -lldap \ -L/usr/local/lib -R/usr/local/lib -llber"
Команда 'make tidy' нужна, только если вы до этого уже собрали Postfix без поддержки LDAP.
Вместо '/usr/local' указывайте актуальное расположение ваших подключаемых файлов и библиотек LDAP. Убедитесь в том, что вы не используете совместно подключаемые файлы и библиотеки LDAP разных версий!!!
Если ваши библиотеки LDAP были собраны с поддержкой Kerberos, вам также нужно включить в эту строку библиотеки Kerberos. Имейте ввиду, что библиотеки KTH Kerberos IV могут конфликтовать с библиотекой Postfix lib/libdns.a, определяющей dns_lookup. Если это происходит, то вам (только для сборки Postfix) скорее всего придётся выполнять компоновку с библиотеками LDAP, в которых отсутствует поддержка Kerberos, поскольку Postfix в любом случае не поддерживает Kerberos-подсоединение к серверу LDAP. Приносим извинения за неудобство.
Если вы используете один из Netscape LDAP SDK, вам понадобится изменить строку AUXLIBS так, чтобы она указывала на libldap10.so, либо libldapssl30.so, либо другой вариант, и, возможно, потребуется использовать подходящую опцию компоновщика (например, '-R'), чтобы исполняемые файлы могли найти эти библиотеки во время исполнения.
Если вы используете OpenLDAP и его библиотеки собраны с поддержкой SASL, то для включения поддержки SASL можете добавить опцию -DUSE_LDAP_SASL к CCARGS. Например:
CCARGS="-I/usr/local/include -DHAS_LDAP -DUSE_LDAP_SASL"
Для использования LDAP-поисков определите источник LDAP в качестве таблицы поиска в main.cf
, например:
alias_maps = hash:/etc/aliases, ldap:/etc/postfix/ldap-aliases.cf
В файле /etc/postfix/ldap-aliases.cf можно указать большое число параметров, в том числе параметры, задействующие LDAP SSL или STARTTLS, а также LDAP SASL. Полное описание смотрите в man-странице ldap_table(5).
Базовый пример использования LDAP для поиска локальных (local(8)
) псевдонимов. Подразумевается, что в main.cf
у вас:
alias_maps = hash:/etc/aliases, ldap:/etc/postfix/ldap-aliases.cf
А в файле /etc/postfix/ldap-aliases.cf у вас:
server_host = ldap.example.com search_base = dc=example, dc=com
При получении письма для локального адреса "ldapuser", который не удалось найти в базе данных /etc/aliases, Postfix будет осуществлять поиск на LDAP-сервере, ожидающем соединения на порту 389 хоста ldap.example.com. Он выполнит анонимное подсоединение, поиск любых записей, атрибут mailacceptinggeneralid которых имеет значение "ldapuser", прочитает значения атрибутов "maildrop" найденных записей (будут интерпретироваться как адреса в формате RFC 822), и на их основе создаст список почтовых ящиков, на которые будет доставлено сообщение.
Если вы хотите хранить в своём каталоге информацию для поиска виртуальных учётных записей, это лишь немного сложнее. Для начала вам нужно убедиться, что Postfix знает о требуемом виртуальном домене. Простой путь сделать это — добавить домен в атрибут mailacceptinggeneralid какой-нибудь записи каталога. Затем вам нужно убедиться, что значения атрибутов mailacceptinggeneralid всех ваших виртуальных получателей дополнены полностью квалифицированными именами своих виртуальных доменов. Наконец, если вы хотите назначить некоторую запись каталога в качестве пользователя по умолчанию для виртуального домена, просто задайте ей дополнительное значение атрибута mailacceptinggeneralid (или его эквивалента согласно своим настройкам каталога) вида "@fake.dom". Именно так, без указания имени пользователя. Если вам не нужен общий пользователь для перехвата писем неизвестным адресатам домена, пропустите этот шаг, и такие письма будут просто отклоняться.
В итоге, у вас может быть такая запись общего пользователя-сборщика почты для виртуального домена:
dn: cn=defaultrecipient, dc=fake, dc=dom objectclass: top objectclass: virtualaccount cn: defaultrecipient owner: uid=root, dc=someserver, dc=isp, dc=dom 1 -> mailacceptinggeneralid: fake.dom 2 -> mailacceptinggeneralid: @fake.dom 3 -> maildrop: realuser@real.dom
Нормальные пользователи могут просто иметь по одному значению атрибутов mailacceptinggeneralid
и maildrop
, например, "normaluser@fake.dom" и "normaluser@real.dom".
Каталог LDAP часто используется для хранения информации о членстве в группах. Есть несколько способов работы с группами в LDAP. Мы покажем ряд примеров в порядке возрастания сложности, но из-за большого количества вариантов и нюансов сможем представить только крошечную часть из множества возможных решений. Мы продемонстрируем:
В приводимых далее примерах будут использоваться схема данных и LDAP-записи, показанные ниже, а именно две записи группы ("agroup" и "bgroup") и четыре записи пользователей ("auser", "buser", "cuser" и "duser"). В группу "agroup" входят пользователи "auser" (1) и "buser" (2), членство которых указывается DN-ссылками в многозначном атрибуте "memberdn", также в ней в многозначном атрибуте "memberaddr" напрямую указаны почтовые адреса двух этих пользователей "auser@example.org" (3) и "buser@example.org" (4). Группа "bgroup" имеет ту же структуру в отношении пользователей "cuser"/"duser" (6)/(7)/(8)/(9), кроме того в "bgroup" также имеется атрибут "maildrop" со значением "bgroup@mlm.example.com" (5):
dn: cn=agroup, dc=example, dc=com objectclass: top objectclass: ldapgroup cn: agroup mail: agroup@example.com 1 -> memberdn: uid=auser, dc=example, dc=com 2 -> memberdn: uid=buser, dc=example, dc=com 3 -> memberaddr: auser@example.org 4 -> memberaddr: buser@example.org
dn: cn=bgroup, dc=example, dc=com objectclass: top objectclass: ldapgroup cn: bgroup mail: bgroup@example.com 5 -> maildrop: bgroup@mlm.example.com 6 -> memberdn: uid=cuser, dc=example, dc=com 7 -> memberdn: uid=duser, dc=example, dc=com 8 -> memberaddr: cuser@example.org 9 -> memberaddr: duser@example.org
dn: uid=auser, dc=example, dc=com objectclass: top objectclass: ldapuser uid: auser 10 -> mail: auser@example.com 11 -> maildrop: auser@mailhub.example.com
dn: uid=buser, dc=example, dc=com objectclass: top objectclass: ldapuser uid: buser 12 -> mail: buser@example.com 13 -> maildrop: buser@mailhub.example.com
dn: uid=cuser, dc=example, dc=com objectclass: top objectclass: ldapuser uid: cuser 14 -> mail: cuser@example.com
dn: uid=duser, dc=example, dc=com objectclass: top objectclass: ldapuser uid: duser 15 -> mail: duser@example.com
В нашем первом варианте использования атрибуты "memberdn" игнорируются, и предполагается, что группы содержат только собственно почтовые адреса в атрибутах "mberaddr", как показано в строках (3), (4), (8) и (9). Цель состоит в том, чтобы сопоставить адрес группы со списком, составленным из значений "mberaddr". Это просто. Опустив разные настройки, связанные с установкой соединения (хосты, порты, параметры подсоединения, тайм-ауты и прочее), мы получим:
simple.cf: ... search_base = dc=example, dc=com query_filter = mail=%s result_attribute = memberaddr $ postmap -q agroup@example.com ldap:/etc/postfix/simple.cf \ auser@example.org,buser@example.org
Мы ищем в поддереве "dc=example, dc=com". В параметре query_filter атрибут "mail" используется для нахождения нужной группы, а параметр "result_attribute", описанный в ldap_table(5), используется для указания того, что значения "memberaddr" из соответствующей группы должны быть возвращены в виде разделённого запятыми списка. Всегда проверяйте таблицы при помощи postmap(1)
с опцией "-q" перед внедрением их в используемый в рабочем окружении конфигурационный файл main.cf
.
В отличие от первого, в нашем втором варианте использования раскрываются атрибуты "memberdn" (1), (2), (6) и (7), происходит следование по DN-ссылкам и возвращаются значения атрибутов "maildrop" пользовательских записей, на которые указывали ссылки. Здесь мы используем параметр "special_result_attribute" из ldap_table(5) для указания того, что в атрибуте "memberdn" содержатся DN нужных нам записей участников группы. Параметр "result_attribute" определяет, какие атрибуты будут возвращены из записей с выбранными DN. Важно подобрать результирующий атрибут так, чтобы он одновременно не присутствовал в объекте группы, поскольку результирующие атрибуты собираются и из группы, и из её членов. В данном случае мы выбрали "maildrop", предположив на минуту, что в записях групп никогда не будет атрибута "maildrop" (атрибут "maildrop", присутствующий в "bgroup", предназначен для демонстрации другого варианта использования). Возвращаемые данные для пользователей "auser" и "buser" извлекаются из атрибутов в строках (11) и (13) приведённого выше примера записей каталога.
special.cf: ... search_base = dc=example, dc=com query_filter = mail=%s result_attribute = maildrop special_result_attribute = memberdn $ postmap -q agroup@example.com ldap:/etc/postfix/special.cf \ auser@mailhub.example.com,buser@mailhub.example.com
Примечание: если нужный результирующий атрибут объекта члена группы также всегда присутствует и в объекте группы, вы получите неожиданные результаты: поиск вернёт также и адрес группы. Это известное ограничение для Postfix версий до 2.4, для устранения которого в Postfix 2.4 введён новый параметр "leaf_result_attribute", описанный в ldap_table(5).
В нашем третьем варианте использования есть некоторые группы, которые разрешаются непосредственно почтовым сервером, а есть другие группы, которые перенаправляются на выделенный хост менеджера списков рассылки для дальнейшего разрешения. Здесь используются две LDAP-таблицы: первая для пользователей и перенаправляемых групп, вторая для групп, которые могут быть разрешены сразу. Предполагается, что группы, требующие перенаправления, никогда не являются вложенными членами тех групп, которые разрешаются напрямую.
no_expand.cf: ... search_base = dc=example, dc=com query_filter = mail=%s result_attribute = maildrop expand.cf ... search_base = dc=example, dc=com query_filter = mail=%s result_attribute = maildrop special_result_attribute = memberdn $ postmap -q auser@example.com \ ldap:/etc/postfix/no_expand.cf ldap:/etc/postfix/expand.cf \ auser@mailhub.example.com $ postmap -q agroup@example.com \ ldap:/etc/postfix/no_expand.cf ldap:/etc/postfix/expand.cf \ auser@mailhub.example.com,buser@mailhub.example.com $ postmap -q bgroup@example.com \ ldap:/etc/postfix/no_expand.cf ldap:/etc/postfix/expand.cf \ bgroup@mlm.example.com
Для негрупповых объектов и групп с отложенным разрешением (тех, которые имеют атрибут "maildrop") в результате поиска возвращается единственное значение почтового ящика (maildrop). Для групп, не имеющих атрибута "maildrop", разрешение происходит также, как в рассмотренном ранее втором варианте использования. В Postfix 2.4 и более новых версиях есть более элегантное решение для этого случая.
Наш финальный вариант использования аналогичен третьему, но на этот раз применяются новые возможности Postfix 2.4. Теперь мы можем использовать лишь одну LDAP-таблицу и нам больше не нужно рассчитывать на то, что перенаправляемые группы никогда не будут вложенными членами разрешаемых групп.
fancy.cf: ... search_base = dc=example, dc=com query_filter = mail=%s result_attribute = memberaddr special_result_attribute = memberdn terminal_result_attribute = maildrop leaf_result_attribute = mail $ postmap -q auser@example.com ldap:/etc/postfix/fancy.cf \ auser@mailhub.example.com $ postmap -q cuser@example.com ldap:/etc/postfix/fancy.cf \ cuser@example.com $ postmap -q agroup@example.com ldap:/etc/postfix/fancy.cf \ auser@mailhub.example.com,buser@mailhub.example.com,auser@example.org,buser@example.org $ postmap -q bgroup@example.com ldap:/etc/postfix/fancy.cf \ bgroup@mlm.example.com
В данном примере отложенное разрешение организуется через атрибут, указанный в параметре "terminal_result_attribute". При наличии в записи этого атрибута, его значение используется как единственный результат, а все остальные попытки разрешения подавляются. При его отсутствии, для конечных объектов, не имеющих атрибутов, указанных в параметре "special_result_attribute" (негрупповых объектов), возвращаются только значения атрибутов, указанных в параметре "leaf_result_attribute", тогда как значения атрибутов из параметра "result_attribute" (непосредственно почтовые адреса членов группы) возвращаются на любом уровне рекурсивного разрешения, а не только для конечных объектов. Этот забавный пример иллюстрирует все возможности разрешения групп в Postfix 2.4.
Также LDAP-таблицы часто применяются для перезаписи отправителей и получателей сообщений, как это обычно выполняется с помощью канонических таблиц Postfix, например, для того, чтобы почта, покидающая ваш сайт, выглядела как "First.Last@example.com" вместо "userid@example.com".
Используемые в этом документе фрагменты схемы данных и имена атрибутов являются лишь примерами. В них нет ничего особенного, кроме, пожалуй, того, что некоторые из них являются значениями по умолчанию в параметрах конфигурации LDAP-таблиц. Вы можете использовать абсолютно любую схему данных и настроить Postfix для работы с ней.
Скорее всего, вам стоит поддерживать значения атрибутов mailacceptinggeneralid уникальными в пределах каталога, а также установить правила заполнения этого атрибута таким образом, чтобы пользователь не смог назначить себе некие специальные значения, к примеру, postmaster или root.
В записи может быть произвольное число атрибутов mailacceptinggeneralid или maildrop. Кроме того, значением атрибута maildrop может быть разделённый запятыми список почтовых адресов. Все они будут найдены и возвращены в ответ на поисковый запрос. Например, можно определить запись, предназначенную для использования в качестве списка рассылки, следующим образом (Внимание! Используется специализированная схема данных, составленная только для этого примера):
dn: cn=Accounting Staff List, dc=example, dc=com cn: Accounting Staff List o: example.com objectclass: maillist mailacceptinggeneralid: accountingstaff mailacceptinggeneralid: accounting-staff maildrop: mylist-owner maildrop: an-accountant maildrop: some-other-accountant maildrop: this, that, theother
Если вы используете LDAP-карту для чего-то помимо разрешения псевдонимов, вам стоит убедиться, что поиск будет иметь смысл. В случае поисков виртуальных учётных записей, значения атрибута maildrop, отличные от адресов электронной почты, обычно бесполезны, поскольку Postfix не сможет определить, кого назначить в качестве владельца, когда доставка выполняется в программу или файл. Значение параметра query_filter может выглядеть примерно так:
query_filter = (&(mailacceptinggeneralid=%s)(!(|(maildrop="*|*")(maildrop="*:*")(maildrop="*/*"))))
И в продолжение темы, даже для псевдонимов, вполне вероятно, что вы не пожелаете, чтобы пользователи определяли себе в качестве доставки программы, включения и т.п. Это может быть особенно актуально на "пустом" сервере, где у них нет локальных учетных записей UNIX, но есть лишь записи в LDAP и Cyrus. Можно позволить подобные вольности только для записей каталога, принадлежащих административной учётной записи, то есть если объект имеет в качестве адреса доставки программу и не принадлежит "cn=root", он не будет возвращён как допустимый локальный пользователь. Стоит хорошенько подумать над безопасной реализацией такой стратегии, учитывая разнообразные варианты этого типа доставки. Возможно, стоит вообще отказаться от обработки подобных ситуаций в LDAP-таблицах, запретив их через грамотно сформированное значение query_filter, и использовать что-то вроде списков majordomo в базе данных локальных псевдонимов.
query_filter = (&(mailacceptinggeneralid=%s)(!(|(maildrop="*|*")(maildrop="*:*")(maildrop="*/*"))(owner=cn=root, dc=your, dc=com)))
LDAP-поиски медленнее, чем поиски в локальных таблицах DB или DBM. Для большинства сайтов они не должны быть узким местом, но всё же неплохо знать, как можно улучшить производительность своей службы каталогов.
Несколько LDAP-карт могут иметь общее LDAP-соединение, если они отличаются только параметрами, связанными с запросами: base, scope, query_filter и т.п. Чтобы воспользоваться этим преимуществом, избегайте необязательных различий в определениях LDAP-карт: порядок подключения к хостам, версия протокола, параметры подсоединения, tls и им подобные должны быть идентичны для разных карт там, где это возможно.
Если у вас есть вопросы, отправляйте их на postfix-users@postfix.org. Пожалуйста, дополните вопрос относящейся к нему информацией о вашей настройке Postfix: связанный с LDAP вывод команды postconf, с какими библиотеками LDAP производилась сборка и какой сервер каталогов вы используете. Если ваш вопрос затрагивает содержимое вашего каталога, включите также соответствующие фрагменты необходимых записей каталога.
ldap:/path/ldap.cf
), требуемая для более безопасного хранения пароля в открытом виде для аутентификации.main.cf
.