Postfix LDAP Howto

Поддержка LDAP в Postfix

Postfix может использовать каталог LDAP в качестве источника для любых своих поисков: aliases(5), virtual(5), canonical(5) и других. Это позволяет вам хранить информацию для своей почтовой службы в реплицируемой сетевой базе данных с детализированным контролем доступа. За счёт отказа от хранения её локально на почтовом сервере администратор получает возможность поддерживать его откуда угодно, а пользователи могут контролировать всё, что вы посчитаете уместным. У вас может быть несколько почтовых серверов, использующих одинаковую информацию, без хлопот и задержек, связанных с необходимостью копирования её на каждый из них.

Темы, раскрываемые в этом документе:

Сборка Postfix с поддержкой LDAP

Данная инструкция подразумевает, что вы собираете 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-поисков определите источник 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         
1: Postfix знает, что fake.dom является действительным виртуальным доменом, если выполняя поиск по этому значению, он получает что-то (значение атрибута maildrop) обратно.
2: Это приведёт к тому, что все письма для неизвестных пользователей домена fake.dom перехватываются этой записью ...
3: ... и попадают в её почтовый ящик (maildrop).

Нормальные пользователи могут просто иметь по одному значению атрибутов mailacceptinggeneralid и maildrop, например, "normaluser@fake.dom" и "normaluser@real.dom".

Пример: раскрытие LDAP-групп

Каталог LDAP часто используется для хранения информации о членстве в группах. Есть несколько способов работы с группами в LDAP. Мы покажем ряд примеров в порядке возрастания сложности, но из-за большого количества вариантов и нюансов сможем представить только крошечную часть из множества возможных решений. Мы продемонстрируем:

  1. запрос групп как списков почтовых адресов;
  2. запрос групп как списков объектов пользователей, содержащих почтовые адреса;
  3. перенаправление специальных списков в неразрешённом виде на отдельный сервер для модерации или иной обработки списков;
  4. обслуживание сложных схем путём управления разрешением и специальной обработки конечных узлов с использованием нового функционала Postfix 2.4.

В приводимых далее примерах будут использоваться схема данных и 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-поисков

Также LDAP-таблицы часто применяются для перезаписи отправителей и получателей сообщений, как это обычно выполняется с помощью канонических таблиц Postfix, например, для того, чтобы почта, покидающая ваш сайт, выглядела как "First.Last@example.com" вместо "userid@example.com".

Информация к размышлению

Обратная связь

Если у вас есть вопросы, отправляйте их на postfix-users@postfix.org. Пожалуйста, дополните вопрос относящейся к нему информацией о вашей настройке Postfix: связанный с LDAP вывод команды postconf, с какими библиотеками LDAP производилась сборка и какой сервер каталогов вы используете. Если ваш вопрос затрагивает содержимое вашего каталога, включите также соответствующие фрагменты необходимых записей каталога.

Благодарности

И, конечно же, Wietse.