В сети довольно мало информации о подобной интеграции. То, что задача решаема — свидетельствуют редкие комментарии на сайтах, но готового решения я не нашёл. Возможно, это обусловлено тем, большинство используют postfix/exim.


Цели статьи:


  1. Описать методику решения задачи, чтобы было проще тем, кто пойдёт по моим следам;
  2. Отвлечь внимание коммьюнити от старого-доброго-древнего postfix и компании.


Введение


В процессе переезда готовой веб/почтовой/серверной инфраструктуры со старого сервера на новые сервера, я столкнулся с необходимостью развернуть почтовую инфраструктуру заново.


Исходная почтовая система разворачивалась в 2012м году. Ansible тогда только зарождался. Системы конфигурирования не были так распространены как сейчас. Автоматизацию работы я тогда любил меньше, чем сейчас, поэтому всё конфигурировалась руками.


Новая система должна была быть построена на докере (что означает максимально подробное описание построения системы "на будущее") и работать в докер кластере.


Конфиги старой системы сохранились, но мне очень не хотелось возвращаться к "dnl" sendmail, куче строк описания логики postfix, непонятному процессу настройки работы amavis+spamasassin, множеству памяти, которое требовалось amavis+spamasassin. Было принято решение поискать альтернативы.


Чтобы никто не говорил "используешь какой-то маргинальный софт потому, что не осилил postfix", я уточню: осилил. Изначальная система состояла из postfix+dovecot+amavisd-new+spamasassin+dkim-proxy+razor+pyzord+dcc.


Забегая вперёд: конечная система состоит из opensmtpd+dbmail+dkim-proxy+rspamd.


Немного теории


opensmtpd — это легковесный почтовый демон, с элементарным процессом конфигурирования от команды OpenBSD. Правила конфигрурированию настолько просты и интуитивно понятны, что сразу запоминаются и позволяют описать десятью строчками полную логику работы почтового сервера.


dbmail — хранилище почты с pop/imap интерфейсом. Основная особенность — хранение почты в базе, что позволяет создавать произвольное число точек входа.


rspamd — почтовая анти-спам система от разработчиков из Рамблера.


Ещё альтернативы? Почему не Zimbra? Почему не ещё какое-то готовое решение вида mail-in-a-box, которое содержит в себе все нужные компоненты?


Zimbra отпадала по причине Java — не хотелось расходовать ресурсы.


mail-in-a-box — опять же все те же postfix и компания.


Описание проблемы


opensmtpd — замечательный демон, но у него есть недостатки, которые не позволяют легко его интегрировать с rspamd.


Это:


  1. Отсутствие поддержки протокола "milter". Данный протокол (расширение) позволил бы интегрироваться с rspamd стандартными средствами.


  2. Отсутствие поддержки фильтров. Разработчик rspamd для интеграции рекомендует использовать фильтры opensmtpd. Разработка же фильтров идёт уже который год, но до сих пор не в продакшене. Существует даже фильтр для rspamd, но до сих пор в отдельной ветке на github.


    После определённых доработок кода откомпилировать и запустить данный фильтр у меня получилось, но он выдавал ошибки в процессе работы и дальше не было желания разбираться в коде.


  3. Отсутствие метода приёма почты кроме как по почтовым протоколам.

Так же, ситуация усложнялась следующими моментами:


  1. Удалённость сервисов друг от друга: демоны работают в докер-контейнерах с разными IP. Фактически, контейнер с opensmtpd и контейнер с rspamd можно представить как работающие на разных серверах.


  2. Разнородность ПО: opensmtpd есть в стабильной версии Alpine Linux (версия linux, которую часто используют в качестве базового образа Docker), но там нет rspamd. И наоборот: rspamd есть в нестабильной версии Alpine, но там не работает opensmtpd.

Итак, в качестве исходной задачи, мы имеем opensmtpd, который на порту 25 ждёт входящую почту и на порту 10029 ждёт почту, которую проверил rspamd.


Решение проблемы


В opensmtpd существуют mda. Вероятно, это расшифровывается как mail delivery agent. Перенаправление письма в mda вызывает запуск внешней программы. Пример правила перенаправления письма:


accept tagged IN from any for domain <domains> userbase <virtual_users> deliver to mda "/usr/local/bin/rspamd.sh %{sender} %{rcpt}" as admin

Здесь мы вызываем некий внешний скрипт, куда передаём адрес отправителя и адрес получателя.


В комплекте с rspamd идёт rspamc — это аналог почтового mta для rspamd. Данная программа позволяет принять на вход письмо, передать его rspamd по HTTP API и выдать ответ.


Интеграция mda и rspamd выглядит следующим образом


/usr/bin/rspamc --mime -h rspamd.example.ru:11333

На STDIN скрипту мы отправляем письмо, указываем адрес rspamd и параметром --mime говорим, что нужно добавить заголовки обработки письма (по которым в дальнейшем будет определяться спам).


После того, как письмо обработано rspamd, его нужно каким-то образом направить обратно в opensmtpd. Но стандартный mta (в комплекте с opensmtpd) умеет отправлять только на порт 25 (мы же ждём проверенное письмо на другом порту).


Решение: формировать общение по почтовому протоколу самим (хорошо, он несложный) и отправлять данные на нужный порт используя netcat.


Итоговый mda скрипт rspamd.sh интеграции opensmtpd и rspamd


#!/usr/bin/env sh

mail_file=$(mktemp)

echo 'HELO localhost' >> $mail_file
echo "MAIL FROM: <$1>" >> $mail_file
echo "RCPT TO: <$2>" >> $mail_file
echo 'DATA' >> $mail_file

/usr/bin/rspamc --mime -h rspamd.example.ru:11333 >> $mail_file

echo '' >> $mail_file
echo '.' >> $mail_file
echo 'QUIT' >> $mail_file

cut_file=$(mktemp)
sed '/Delivered-To/d' $mail_file > $cut_file
rm "$mail_file"

count=0; IFS=''; while read -r line ; do if [ "$count" -gt "5" ]; then sleep 0.05; else sleep 0.1; fi; echo "$line"; count=$((count+1)); done < "$cut_file" | netcat localhost 10029

rm "$cut_file"

Особенности данного скрипта:


  1. Отправлять данные через netcat следует с задержками после каждой строки этапа установки соединения. Для этого мы делаем задержки между отдачей строк.
  2. Из исходного письма следует вырезать заголовок "Delivered-To", который добавляет opensmtpd. Иначе, opensmtpd посчитает данное письмо зациклившимся.

Решение проблемы совмещения opensmtpd и rspamd в одном контейнере: использование Docker образа на основе Debian sid, куда подключается репозиторий rspamd и из него устанавливается свежая версия. Пример установки:


wget -O- https://rspamd.com/apt-stable/gpg.key | apt-key add - && echo "deb http://rspamd.com/apt-stable/ sid main" > /etc/apt/sources.list.d/rspamd.list && apt-get update && apt-get install --no-install-recommends --no-install-suggests -y rspamd

Итоги


В результате перехода с postfix+amavis на opensmtpd+rspamd я получил простоту конфигурации сервиса, малое потребление памяти и меньше спама на почту.


Реализацию итогового Docker контейнера можно посмотреть здесь.

Поделиться с друзьями
-->

Комментарии (10)


  1. Dr_Wut
    29.01.2017 01:59
    +1

    У меня только один вопрос — зачем почта в докере? (Мне серьезно интересно — зачем?)
    P.S. За статью спасибо, узнал про opensmtpd и rspamd :)


    1. neenik
      29.01.2017 03:01

      Для простоты описания настройки сервиса/инфраструктуры. Собственно, всё то, что даёт докер.
      Для простоты/быстроты разворачивания: почтовый сервис (9 контейнеров) разворачивается (например, nomad'ом) за пару минут.

      Ещё потому, что докер — это болезнь. Попробовал один раз — и отказаться уже не можешь. :)


      1. Dr_Wut
        30.01.2017 00:33

        А как часто вы раскатываете новые почтовые сервисы? И мне вто тоже кажется это больше обусловлено «докером как болезнью» :)))


  1. jean
    29.01.2017 02:14

    Хотелось бы предостеречь от использования dbmail тех, кто только выбирает себе IMAP / POP сервер. Это может показаться хорошей затеей — хранить почту в БД, но dbmail — очень сырой продукт и фактически не развивается. Мучились с ним несколько лет, постоянно что-то ломалось и не работало (250 пользователей, 200 Гб база). В итоге наткнулись на то, что при больших значениях id сообщения в базе все начинает просто еле шевелится.

    Перешли на dovecot в итоге и всем довольны. Недовольны только тем, что с начала его не взяли)


    1. neenik
      29.01.2017 03:08

      База почти всегда однозначным образом ускоряется: партиции, индексы. И преимущества базы (независимость от конкретной файловой системы на конкретном сервере) могут играть большую роль, чем скорость.

      Но для больших, нагруженных почтовиков согласен, что файлы будут быстрее.


      1. rrpv
        29.01.2017 12:57

        База почти всегда однозначным образом ускоряется: партиции, индексы.

        В том-то и дело, что "… и вам придется это делать".


        Для нагруженных почтовиков — файлы будут быстрее.

        А для ненагруженных DBMail тем более не нужен — им нет необходимости "создавать произвольное число точек входа", а других преимуществ нет, одни недостатки.


        Тот же Dovecot создает какие-то нужные ему индексы "из коробки", без дополнительных настроек.
        Установил и забыл.


        В случае DBMail — почта гуляет внутри сервера между программами: сначала подгружается в СУБД, там кешируется, затем передается даймону DBMail, кешируется в нем (нужно же получить полный результат SQL-запроса), и только затем передается почтовому клиенту.


        Зачем нужно всё это кратное усложнение процесса и соответствующее увеличение нагрузки на сервер, если можно просто сразу отдать содержимое письма из файла?


        И это мы еще не говорим о разных "вкусностях" Dovecot, которые, например, позволяют создать в нем папку "Спам" и интегрировать скрипты, обучающие rspamd по факту перемещения почты в/из этой папки.


        Да тот же DBMail даже SSL не умеет, судя по его Wiki — там предлагается SSL настраивать через stunnel. Зачем всё это надо?


  1. cebka
    29.01.2017 13:17

    Есть ряд замечаний по статье. Во-первых, режим --mime предназначен не для реинжектирования письма по SMTP, а для того, чтобы передать готовое письмо на LDA, а не MTA. Проблема там ровно в том, что Rspamd не добавляет Received заголовок, отчего запросто можно получить mail loop. В теории, в 1.5 можно сделать поддержку правильного реинжектирования на базе lua_tcp и убрать все эти странные костыли на nc.


    Тем не менее, все такие решения страдают одной неприятной проблемой: в них крайне сложно реализовать выборочный грейлистинг, который я считаю одним из самых эффективных методов борьбы со спамом: за время грейлистинга могут успеть среагировать спамтрапы и всякие репутационные списки: surbl, ip_score, rbl и прочее. Именно поэтому я довольно много общался с разработчиком opensmtpd на предмет форсирования проекта с фильтрами, но, увы, никакого прогресса по фильтрам я не вижу.


    Ну и последний момент: а зачем вам еще сущность в виде dkim-proxy? Rspamd прекрасно работает как для проверки DKIM, так и для генерации подписей.


    1. neenik
      29.01.2017 15:18

      Всё, описанное в статье, если говорить прямо — не очень эффективный по ресурсам набор костылей. Отсюда и --mime и удаление Delivered-To, чтобы избежать лупа.

      По поводу грейлистинга и фильтров — поддержу на все 100%. Если бы были фильтры, то из коробки бы всё заработало. Судя по прогрессу — может, через полгода будут фильтры.

      dkim-proxy — чтобы логика обработки исходящих была прозрачной (и unixway). Получил opensmtpd письмо от внутренних систем на выделенный порт, отправил его на подпись dkim-proxy, тот его подписал и перенаправил на другой выделенный порт. А rspamd занимается только проверкой dkim/dmarc/spf, да.


  1. zirf
    30.01.2017 01:39

    но мне очень не хотелось возвращаться к "dnl" sendmail


    Некоторым образом sendmail.mc это не конфиг sendmail, а его исходник для m4, конфиг называется sendmail.cf и написан на древнемарсианском. Всякий, кто мог редактировать его вручную считался небожителем, и всякий, кто лез в него второй раз — сумасшедшим.
    Очень симпатичный почтарь — courier-mta. Да, courier-IMAP кусок от него. Но установка его требует некоторого навыка. Он идет в виде исходника, но в комплекте есть spec для сборки rpm, причем очень корректно, не от root (просто не дает). Вот тут засада — это почтовик с богатейшим функционалом и для сборки бинарных файлов нужна машина с большим количеством dev-пакетов на различную тематику. Из антивирусников его DrWeb поддерживает (в свое время давным-давно предложили его включить). В настройке он прост, легко интегрируется с чем хотите, просто альтернатив sendmail появилось в какой-то момент много, важным качеством была простота настройки. И подозреваю, что на популярные ныне МТА (частоту установок) влияло наличие документации и распространенность дистрибутивов, где это была основная альтернатива sendmail, очень мощному, но вечно дырявому и каверзному в развертывании.


  1. Temmokan
    01.02.2017 07:24

    Аналогичный вопрос про Exim — рассматривался ли как вариант?

    Уже который год работаю с композицией exim + clamav + dspam + dovecot. Компактно (если не считать ощутимого расхода памяти ClamAV), стабильно и нет проблем добавлять фильтры и всё такое.