Інтеграція поштового анти-спаму rspamd з opensmtpd

У мережі досить мало інформації про подібної інтеграції. Те, що завдання вирішується — свідчать рідкісні коментарі на сайтах, але готового рішення я не знайшов. Можливо, це обумовлено тим, більшість використовують 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.ua:11333

На STDIN скрипту ми відправляємо лист, вказуємо адресу rspamd і параметром --mime говоримо, що потрібно додати заголовки обробки листа (за якими надалі буде визначатися спам).
Після того, як опрацьовано лист rspamd, його потрібно якимось чином направити назад в opensmtpd. Але стандартний mta (в комплекті з opensmtpd) уміє відправляти тільки на порт 25 (ми ж чекаємо перевірене лист на іншому порту).
Рішення: формувати спілкування за поштовим протоколу самим (добре, він нескладний) і відправляти дані на потрібний порт використовуючи netcat.
Підсумковий mda скрипт rspamd.sh інтеграції opensmtpd і rspamd
#!/usr/bin/sh env

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.ua: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 контейнера можна подивитися тут.
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.