ZImbra: нетривиальная маршрутизация почты - часть 2

  • LDAP
Первая часть тут

Положим, поставила перед вами нелёгкая судьбина следующую задачу: добавить в Zimbr'у alias, он же псевдоним. Но псевдоним тот не простой, а виртуальный, указывающий не на пользователя в локальном домене, обслуживаемом Zimbra, а на некий «внешний» почтовый адрес.
Как законопослушный гражданин, вы наверняка первым делом загрузите интерфейс администрирования Zimbra и в меню Создать выберете «Псевдоним». После совершения указанной манипуляции пред ваши очи предстанет такое вот окно:

Читать дальше →

Индексы not equal и pres

  • LDAP
Индекс pres нужно использовать только для очень редко встречающихся, но часто «искомых» атрибутов
Индекса not equal не существует в природе, но _некоторые_ (сдаётся, мне что двузначные, то есть флаговые например ) атрибуты могут создавать индекс not equal на основании индекса equal. В общем для zimbraIsSystemResource, который таки флаг, я индекс eq добавил, а там хоть трава не сохни.
Вообще полезно бывает в 25-й раз одну и ту же страницу документации читать: склероз побуждает к неожиданным открытиям, в особенности если раньше читал то же самое, но по другому поводу

Ах да, ещё лучше бы держать логи низкоуровневой БД и собственно данные на разных дисках.
Цитирую OL Admin Guide:
Use fast subsystems. Put each database and logs on separate disks configurable via DB_CONFIG:
# Data Directory
set_data_dir /data/db

# Transaction Log settings
set_lg_dir /logs

Эх, где бы эти раздельные диски ещё найти в наш век тотального RAID'а с LVM'ом…

P.P.S. А вообще по моим наблюдениям ту же MySQL нередко используют почти read-only.

MultiMaster vs. Mirroring

  • LDAP
По возможности не используйте Multimaster-репликацию в её полноценном виде:

— теоретически неограниченое количество мастер-серверов,

— каждый мастер-сервер может принимать реплики изменений с любого другого мастер-сервера.

Дело в том, что это работает только в том случае, если все мастер-сервера создаются с нуля и практически одновременно. Это именно так в случае с простым тестом 050-multimaster, на который так любят ссылаться разработчики OpenLDAP. Тем не менее даже такой вроде бы стабильно работающий кластер взаимнореплицируемых серверов может потерять ноду… А потом вторую… В особенности это касается тех случаев, когда нод больше трёх: число три для режима Multimaster'а в OpenLDAP является каким-то магическим порогом, за которым начинаются эксперименты над критически важными данными с плохо прогнозируемыми последствиями.
Mirroring (зеркалирование) — технически тот же MultiMaster (найдите отличия в конфигурации? olcServerID?), но это иная стратегия репликации. Эта стратегия предполагает, что в штатном режиме работы запись производится лишь на одном сервере, а на второй сервер изменения пересылаются репликой. При этом чтение может осуществляться одновременно с двух серверов при помощи внешнего балансирующего нагрузку фронтэнда (не входит в поставку OpenLDAP можно использовать прокси-режимы работы OL). В случае отказа сервера, принимающего операции записи от клиентов, их начинает принимать неактивная часть «зеркала». Как только «отвалившаяся» часть зеркала поднимется, все операции записи, произведённые за время простоя, будут приняты репликой.
В общем, на самом деле, подчёркиваю, никакой принципиальной разницы между мультимастером и зеркалированием нет, кроме собственно количества нод. Но использование описанной стратегии даёт гораздо более предсказуемый результат, даже если вы не используете никаких внешних фронтэндов и все переключения осуществляете вручную.

P.S. Да, и в любом случае backup often

Одна из распространённых проблем репликации

  • LDAP
Если ваша база OpenLDAP упорно отказывается реплицироваться, запустите сервер, на который вы хотите залить реплику, с ключом -d 16384 (отладка механизма репликации). И если там будет явная «ругань» на то, что с мастер-сервера невозможно получить entryUUID для некоторых записей, это значит, что в исходном каталоге не хватает служебных атрибутов, без которых репликация действительно не пойдёт. Отложим обсуждение вопроса о том, почему так бывает, просто пофиксим эту проблему:
Если база относительно небольшая, переведите её в read-only и сделайте полный slapcat:
$ echo 'dn: olcDatabase={номер_базы}тип_бэкенда,cn=config changeType: modifyreplace: olcReadOnlyolcReadOnly: TRUE' | \ ldapmodify -x -D cn=config -Wbr /&
$ slapcat -F /path/to/config/dir -n номер_базы & my_db.ldif

А теперь… физически удалите файлы базы и залейте LDIF-дамп базы, полученный на шаге 1, обратно:
rm -f /path/to/db/files/*
slapadd -F /path/to/config/dir -n номер_базы -l my_db.ldif
chown -R openldap_user.openldap_group /path/to/db/files/

Примечание: под «номером базы» подразумевается то число, которое проставлено для этой базы в cn=config
То есть, например, для DN=olcDatabase={3}hdb,cn=config номер базы соответственно равен трём. Для самой cn=config номер всегда равен нулю (т.е. это всегда olcDatabase={0}config,cn=config)

Сборка OpenLDAP для сервера-реплики

  • LDAP
Если нужно собрать реплику на чистом сервере полностью аналогично тому, как был собран мастер, делаем так:

1. Качаем и распаковываем свежую версию сабжа:
wgеt ftp://ftp.openldap.org/pub/OpenLDAP/openldap-release/openldap-2.4.23.tgz -O Download/openldap-2.4.23.tgz
tar -xvf Download/openldap-2.4.23.tgz -С Compile/

(предполагается, что pwd=$HOME, а в $HOME есть каталоги Download и Compile)

2. Устанавливаем зависимости. В yum-based rpm-дистрибутивах это выглядит так:
sudo yum install gcc gcc-c++ libtool-ltdl-devel openssl-devel db4-devel

3. Собираем OpenLDAP
Раз это сервер реплики, то можно и нужно ничего нового не придумывать, а просто скопировать его опции сборки из исходников мастер-сервера:

На мастер-сервере:
cd Compile/openldap-2.4.21
scp config.log <replica_host>:Compile/openldap-2.4.23

На реплике (не путать со слэйвом, реплика может быть и вторым мастер-сервером, если используется multimaster):
cd Compile/openldap-2.4.23
eval `sed -n $(\%\$ \./configure%,/^$/p' config.log | tr -d '\n' | sed -r 's%^.+(\./configure)%\1%')
make depend && make && sudo make install

Как видите, в моём случае версии OpenLDAP для реплики и мастер-сервера не совпадают, но в ничего страшного в этом нет, если, конечно, разница в версиях не слишком велика. В моём случае мастер-сервер довольно активно используется, поэтому обновлять его приходится редко.
Команда «eval ...» извлекает из файла config.log строчку вызова ./configure, использовавшуюся для сборки мастер-сервера, и выполняет получившуюся команду

sudo+ldap в Calculate Directory Server

  • LDAP
Будьте внимательны: в популярном у ваятелей LDAP-based архитектур дистрибутиве CDS (Calculate Directory Server) sudo читает отнюдь не /etc/ldap.conf, а что-то другое. То есть конечно если вы внимательно изучали документацию по CDS, то знаете, что именно должен читать sudo в данном дистрибутиве, я же предпочёл попросту скачать свежую версию с офсайта sudo.ws и собрать её со следующими опциями:
./configure --prefix=/usr --with-ldap --with-ldap-conf-file=/etc/ldap.conf -with-ldap-secret-file=/etc/ldap.secret

Чудеса на PADL.COM'е

  • LDAP
Опытным путём сегодня благополучно выяснил, что в nss_ldap используется в режиме «nss_schema rfc2307bis» знаете какой атрибут членства в группе? uniqueMember! Что в этом необычного? А то, что в последней редакции RFC 2307bis, (которая так же, как и все предыдущие не утверждена IETF, а потому не совсем понятно, чего ради её тот же OpenDS использует по дефолту), в качестве атрибута членства в группе, хранящего полный DN, предлагается member, а не uniqueMember! Об этом по сути нигде толком не сказано, поди догадайся…
Кстати, само описание posixGroup в схеме я предлагаю в таком случае хакнуть при первой же возможности и сделать его следующим:
1.3.6.1.1.1.2.2 NAME 'posixGroup' DESC 'Abstraction of a group of accounts' SUP top 
STRUCTURAL MUST gidNumber MAY ( cn $ userPassword $ uniqueMember $ memberUid $ description )

Здесь cn вынесен в MAY атрибуты и добавлен MAY-атрибут uniqueMember
Я конечно понимаю, что это некоторое отклонение от стандарта, но… к сожалению иногда и стандарты страдают «несовершенством». Особенно это касается RFC 2307bis, где с одной стороны posixGroup стал вдруг AUXILIARY, что вынуждает добавлять в стек структурный класс, а с другой стороны — в objectClass'ах groupOfNames и groupOfUniqueNames, содержащих типы атрибутов member и uniqueMember соотв., они заявлены как MUST. Из сказанного следует, что даже если Member'ы формируются оверлеем dynlist, Вы всё равно обязаны постоянно держать в записи нечто вроде «uniqueMember: cn=dummy».
Редактирование же определения posixGroup в указанном ключе позволит вам избавиться от необходимости изворачиваться, стряпая противоестественного вида стек objectClass'ов с лишними значениями атрибутов или добавляя туда extensibleObject, что на мой взгляд — тоже хак в обход схемы.

Впрочем, всё сказанное касается исключительно тех, кто использует DN'ы для членов группы, для обычного memberUid'а хватает стандартной nis.schema, соответствующей RFC 2307

Как сделать просто ноду, "без прикрас"?

  • LDAP
Если нужно добавить элементарный узел в дерево LDAP, пользуйтесь чудесным objectClass'ом «applicationProcess» из RFC 2256.
Вот как выглядит типичный узел с objectClass=applicationProcess:
dn: cn=Accounts,cn=Security
objectClass: applicationProcess
cn: Accounts

Описание applicationProcess:
objectClasses: ( 2.5.6.11 NAME 'applicationProcess' DESC 'RFC2256: an application process' 
SUP top STRUCTURAL MUST cn MAY ( seeAlso $ ou $ l $ description )

Поскольку непонятно, что это ещё за application process такой (thread что ли?), то я думаю, нет ничего противоречащего «букве и духу» LDAP в использовании данного objectClass'а для создания узлов без дополнительной смысловой нагрузки…

DNS+LDAP

  • LDAP
Лучшим решением для интеграции DNS с LDAP является PowerDNS.
Почему?
1) Очень прост в настройке
2) Один объект используется для A и PTR-записей
3) В одном объекте можно указать сколько угодно A-записей (просто указываешь IP и хоть тысячу имён хостов к нему впридачу)
4) Отличная схема, в которой нет ничего лишнего и есть много полезного
5) В итоге — самое главное, DNS-зона получается очень наглядной, даже лучше, чем в Active Directory

Почему нельзя использовать BIND+LDAP? Можно конечно, только вместо преимуществ вы получите какой-то слабочитабельный бред в своём Каталоге, который не годится ни для чего, кроме собственно DNS.

LDAP как источник аутентификации

  • LDAP
Две мои статьи на тему LDAP-аутентификации — написаны относительно давно, но для ознакомления с вопросом должно быть в самый раз:
Сервер каталогов LDAP как источник аутентификации — учётные записи
Сервер каталогов LDAP как источник аутентификации — интеграция с AD

Как научиться работать с LDAP?

  • LDAP
Ответом на это, разумеется, может быть только RTFM.
А именно, лучшей книгой в онлайн на эту тему, бесспорно, является опубликованный на сайте zytrax.com хрестоматийный учебник «LDAP for Rocket Scientists». Несерьёзное название книги полностью соответствует стилю изложения: лёгкому, слегка ироничному и максимально доходчивому. Собственно. авторы просто не хотели называть её «LDAP для Чайников» — это было бы похоже на моветон, да и сразу понижало бы в глазах потенциального читателя важность и полезность данной работы.
Читать учебник от корки до корки особого смысла, на мой взгляд, не имеет: он содержит множество примеров и различной практически полезной информации, так что «если срочно» (а оно почти всегда так и бывает), ищите в нём ответы на свои конкретно поставленные вопросы, да обрящете. Во всяком случае, зачастую это куда полезнее чтения сильно фрагментированного, непоследовательного, находящегося в перманентном состоянии дописывания руководстве OpenLDAP Administration Guide, и это даже при том, что после «LDAP for Rocket Scientists» именно документация проекта OpenLDAP является, на мой взгляд, наиболее толковой.

P.S. Я очень признателен Zytrax'у за выложенные на их сайте книги, и не только по LDAP, но и по DNS-серверу ISC BIND, например. Зитракс — это вообще отличный пример того как коммерческий проект может без каких-то значительных вложений сделать полезное и нужное дело для всех.

schema2ldif конвертер

  • LDAP
Скрипт для преобразования схем
из формата .schema в формат .ldif, пригодный для загрузки в динамическую конфигурацию cn=config. Необходимый параметр — имя файла схемы без расширения, который нужно преобразовать. Скрипт отправляет результат в стандартный поток вывода, откуда вы его можете через пайп перенаправить утилите ldapadd или просто сохранить в файл.

#!/bin/bash
schemaFile="$1"
[[ -f $schemaFile && -r $schemaFile ]] || exit 1
schemaName=${schemaFile##*/}
schemaName=${schemaName%.*}
sed -r \
 -e '/^\s*(#.*)?$/d' \
 -e 's%^\s+%  %' \
 -e 's%^objectclass\s+%olcObjectClasses: %I' \
 -e 's%^attributetype\s+%olcAttributeTypes: %I' $schemaFile | \
  sed "1idn: cn=$schemaName,cn=schema,cn=config\nobjectClass: olcSchemaConfig\ncn: $schemaName"

Это, наверное, самый простой и самый немудрёный schema2ldif из всех, когда либо сочинённых. Но мне его обычно хватает.
А если вам нужен продвинутый вариант конвертера — пожалуйста, один есть прямо в поставке OpenLDAP (тоже на shell, тоже называется schema2ldif), а другой, на мой взгляд, самый развитый, написан на Perl'е, и он вот здесь: storm.alert.sk/soft/schema2ldif/schema2ldif

UPD(2013.05.23): Тот, который на Perl'е, создаёт LDIF'ы для какого-то другого LDAP-сервера, не для OpenLDAP точно!

Лучший графический LDAP-клиент

  • LDAP
Уже очень давно пользуюсь во всех отношениях приятным LDAP-клиентом LDAP Browser/Editor. Эта компактная кроссплатформенная программа на Java с открытым исходным умеет всё или почти всё (не умеет, например, картинки JPEG напрямую в каталог запихивать). Её ближайшим конкурентом можно назвать Apache Directory Studio — клиент более функциональный, интеллектуальный и навороченный, но и более требовательный к ресурсам. Я предпочитаю пользоваться в основном LDAP Browser/Editor'ом и только в каких-то редких случаях — Apache Directory Studio. Из редких случаев стоит упомянуть работу со схемой, просмотр и редактирование Active Directory, а также загрузку любых файлов в каталог (для чего он совершенно не предназначен, поэтому такое кощунство требуется делать действительно редко).

И да, phpLDAPAdmin — штука довольно недоразвитая, ненаглядная и тормозная (как и большинство навязываемых нам «супер-пупер» веб-технологий), поэтому пользоваться ей рекомендую лишь в тех случаях, когда требуется админить LDAP-сервер удалённо из любой точки планеты, и не только под nix'ами, но и под форточками. Но по жизни для нервной системы полезнее будучи на Багамах всё же скачать автономный LDAP-клиент и пользоваться им.

Отличный обзор LDAP Browser/Editor можно найти на сайте LDAP-сервера OpenDS: www.opends.org/wiki/page/LDAPBrowserEditor Правда, указанная там ссылка на домашнюю страничку автора неактуальна уже (видимо, автор прекратил разработку или продолжил её в составе какого-то другого ПО). Тем не менее, программа очень популярна и скачать её можно во многих местах, например, здесь: www.novell.com/communities/files/Gawor_ldapbrow..., а RPM-пакет — здесь: rpm.pbone.net/index.php3/stat/4/idpl/11310306/d...

LDAP-клиенты: SymLabs LDAP Browser

  • LDAP
Написанный на Java LDAP-клиент полукоммерческого происхождения.
1) Под Mandriva Linux установился с правами, ограничивающими доступ даже на запуск исключительно админскими полномочиями (из чего видно, что сами разработчики LB работают в nix только под root'ом)
2) Квадратики вместо русских букв — просто фатальная ошибка
3) Возможности настройки ограничиваются выбором темы, используемой стандартным для Java откровенно уродливым GUI-движком

После того, как я попробовал это чудо, понял, что SymLabs LDAP Proxy, да ещё за деньги, меня совсем не интересует — пусть сами пользуются

Преобразование из objectSid (Active Directory) в sambaSID (Samba schema)

  • LDAP
echo -n 'AQUAAAAAAAUVAAAAW9a4vvY/d/dUSY8vWA0AAA==' | \
perl -MMIME::Base64 -0777 -ne 'my $a=decode_base64($_);
print "S-" . unpack("C",substr($a,0,1)) . "-" . unpack("C",substr($a,7,1));
for $l (0 .. unpack("C",substr($a,1,1))-1) { 
 print "-" . unpack("I",substr($a,8+$l*4,4));
};
print "\n";'


@настроение: перемен, мы ждём перемен!

Операция запроса схемы

  • LDAP
Для запроса информации о действующей схеме LDAP-каталога прежде необходимо выполнить Операцию запроса возможностей, получив значение атрибута subschemaSubentry.
ldapsearch -x -H ldap://host:port -LLL -b "" '(objectClass=*)' subschemaSubentry

Полученное значение используется в качестве Отличительного имени базы поиска (baseDN) в Операции запроса схемы, которую можно описать так:
BIND анонимный;
* База поиска baseDN равна значению атрибута subschemaSubentry, возвращаемого Операцией запроса возможностей;
* Глубина поиска scope указана как base;
* Фильтр поиска: (objectClass=*);
* Перечень запрашиваемых атрибутов: либо явное перечисление, либо "+" (ВНИМАНИЕ! "*" не покажет значения служебных атрибутов, содержащих всю полезную информацию);

Например, при использовании LDAP-клиента из поставки OpenLDAP Операция запроса схемы может выглядеть так:

ldapsearch -x -H ldap://host:port -LLL -b «cn=Subschema» '(objectClass=*)' ldapSyntaxes matchingRules

Операция запроса возможностей

  • LDAP
В стандарте LDAP определена специальная операция, позволяющая клиентам получать информацию о поддерживаемых сервером версиях протокола и возможностях LDAP-сервера. Эта команда является надстройкой (расширением) для операции search и выполняется при следующем сочетании параметров последней:

* BIND анонимный
* База поиска baseDN указана как "" (пустая строка)
* Глубина поиска scope указана как base
* Фильтр поиска: (objectClass=*)

Например, при использовании LDAP-клиента из поставки OpenLDAP команда запроса возможностей может выглядеть как:
ldapsearch -x -H ldap://host:port -LLL -b "" '(objectClass=*)' suppotedControls supportedCapabilities

Открылся форум сообщества LDAP-специалистов

  • LDAP
Рад сообщить об открытии простенького форума, полностью посвящённого LDAP-технологиям.
На этом форуме сейчас вы можете задавать вопросы мне, а в будущем — и другим LDAP-специалистам. Все вопросы будут рассматриваться предельно оперативно, ни одно обращение не останется без внимания.

Добро пожаловать!

Анонс LDAPCon 2009

  • LDAP
20 и 21-го сентября в рамках организованной LinuxFoundation конференции LinuxCon 2009 пройдёт форум LDAPCon 2009. Место проведения — отель «Portland Marriott Downtown Waterfront», город Портланд, штат Орегон, США.
2-я интернациональная Конференция по LDAP (LDAPCon 2009) — это технический форум для IT специалистов, интересующихся LDAP-технологиями и всем, что с ними связано: серверы каталогов, приложения для управления каталогами, управление аутентификацией и контролем доступа, мета-каталоги. 1-я интернациональная Конференция по LDAP прошла в 2007 году в Германии.
Основное внимание на LDAPCon 2009 будет уделено реализации и интеграции серверов LDAP и LDAP-совместимых (а также, разумеется, и LDAP-ориентированных) приложений. Данное мероприятие предоставляет отличную возможность встретиться поставщикам и разработчикам ПО, активным и будущим участникам LDAP-сообщества с целью обмена полезной информацией и накопленным опытом в области стратегий развёртывания и обслуживания каталогов, взаимодействия серверов и приложений, обсуждения возможностей применения LDAP в новых проектах, получения информации о самых современных тенденциях и разработках в области LDAP-технологий.

Официальный язык конференции — английский.

Краткое функциональное описание протокола LDAP

  • LDAP
(копия моего материала, опубликованного на Wikipedia)
В протоколе LDAP определены следующие операции для работы с Каталогом:
— Операции подключения/отключения
— Подключение (bind) — позволяет ассоциировать клиента с определённым объектом Каталога (фактическим или виртуальным) для осуществления контроля доступа для всех прочих операций чтения/записи. Для того, чтобы работать с Каталогом, клиент обязан пройти аутентификацию как объект, отличительное имя (Distinguished Name) находится в пространстве имён, описываемом Каталогом. В запросе операции bind клиент может не указывать отличительное имя, в таком случае будет осуществлено подключение под специальным псевдонимом anonymous (обычно это что-то наподобие гостевой учетной записи с минимальными правами)
— Отключение (unbind) — позволяет клиенту в рамках сеанса соединения с LDAP-сервером переключиться на аутентификацию с новым отличительным именем. Команда unbind возможна только после аутентификации на сервере с использованием bind, в противном случае вызов unbind возвращает ошибку
— Поиск (search) — чтение данных из Каталога. Операция сложная, на вход принимает множество параметров, среди которых основными являются:
— База поиска (baseDN) — ветка DIT, от которой начинается поиск данных
— Глубина поиска (scope) — может иметь значения (в порядке увеличения охватываемой области): base, one, sub
    base — поиск непосредственно в узле — базе поиска
    one — поиск по всем узлам, являющимся прямыми потомками базового в иерархии, т.е. лежащим на один уровень ниже него
    sub — поиск по всей области, нижележащей относительно базы поиска (baseDN)
— Фильтр поиска (searchFilter) — это выражение, определяющее критерии отбора объектов каталога, попадающих в область поиска, задаваемую параметром scope. Выражение фильтра поиска записывается в обратной (префиксной) польской нотации, состоящей из логических (булевых) операторов и операндов, в свою очередь являющихся внутренними операторами сопоставления значений атрибутов LDAP (в левой части) с выражениями (в правой части) с использованием знака равенства.
Логические операторы представлены стандартным «набором»: & (логическое «И»b), | (логическое «ИЛИ»b) и! (логическое «НЕ»b).
Пример фильтра поиска:
(&(!(entryDN:dnSubtreeMatch:=dc=Piter,dc=Russia,ou=Peoples,dc=example,dc=com))(objectClass=sambaSamAccount)
(|(sn=Lazar*)(uid=Nakhims*)))

— Операции модификации — позволяют изменять данные в Каталоге, при этом в понятие модификации входит как добавление, удаление и перемещение записей целиком, так и редактирование записей на уровне их атрибутов. Подтипы модификации:
— Добавление (add) — добавление новой записи
— Удаление (delete) — удаление записи
— Модификация RDN (modrdn) — перемещение/копирование записи
— Модификация записи (modify) — позволяет редактировать запись на уровне её атрибутов,
добавляя новый атрибут или новое значение многозначного атрибута (add)
удаляя атрибут со всеми его значенями (delete)
и заменяя одно значение атрибута на другое (replace)
— Операция сравнения (compare) — позволяет для определённого отличительного имени сравнить выбранный атрибут с заданным значением