Pull to refresh

Отправка почты из Docker-контейнера (докеризация postfix и sasl)

Reading time6 min
Views28K
Когда я расположил приложение в Docker-контейнере и попробовал отправить email на почтовый сервер в другом Docker-контейнере, столкнулся с непредвиденной проблемой. Почтовый сервер postfix по умолчанию отправляет почту на произвольный домен получателя только от локального клиента. Все остальные домены нужно прописывать в параметре relay_domains, и если параметр mynetwors настроен правильно, то почта будет отправляться на перечисленные в параметре relay_domains домены с клиента из mynetwors.

В принципе, мне этого было достаточно, т.к. приложение теоретически должно было отправлять почту на ровно один корпоративный почтовый сервер. Но такое решение меня не очень устраивало, потому что задача может поменяться в любой момент. Поэтому, я попытался настроить sasl-авторизацию, которая позволяет отправлять почту авторизованным пользователям на произвольный домен.


Первым решением, которым я попробовал воспользоваться — это установить postfix вне контейнера Docker и оправлять на него прямо на порт 25 сообщения с клиента из контейнера Docker. Конечно, меня ожидало разочарование, т.к. localhhost внутри контейнера не имеет ничего общего с localhost вне контейнера.

Следовательно пришлось бы обращаться к postfix не через localhost. Да и изначально цель была такая, чтобы все нужное установить в контейнерах, и не зависеть от окружения на сервере. То есть postfix желательно было установить в контейнере.

Дополнительным плюсом установки postfix внутри контейнера является его полная закрытость от внешнего мира, если только явно не опубликовать его порт в docker-compose, что естественно легче контролировать, чем экзотические параметры в конфигурационных файлах самого postfix.

Для того чтобы можно было обращаться к postfix серверу, который работает внутри контейнера, нужно настроить авторизацию. Самым популярным решением является авторизация sasl. Я ее и решил настроить с использованием sasldb2. Как оказалось не так уж много подробных инструкций об установке sasl для postfix с использованием sasldb2. Некоторые инструкции содержали устаревшую информацию и не содержали нужных сведений. В результате, с первого раза авторизация упорно отказывалась работать. Как оказалось, две основные причины были: использование postfix сервером файловой системе в «песочнице» /var/spool/postfix/, о которой ничего не знает sasl, а также необходимость раздачи прав на файл базы данных /etc/sasldb2, который создает пользователь sasl — пользователю postfix.

Результирующий файл Dockerfile достаточно прост, хотя при поиске решения пришлось повозиться, в основном с правами пользователей, о чем я расскажу немного подробнее.

FROM ubuntu:xenial

ARG UID

RUN \
  useradd -u $UID www-arc && \
  apt-get update && apt-get install tzdata && \
  echo Europe/Kiev | tee /etc/timezone && \
  dpkg-reconfigure --frontend noninteractive tzdata && \
  apt-get install -y postfix rsyslog sasl2-bin && \
  postconf -e "mydestination = localhost" && \
  postconf -e "myhostname = example.com" && \
  postconf -e "always_bcc = www-arc@localhost" && \
  postconf -e "smtpd_sasl_auth_enable=yes" && \
  postconf -e "broken_sasl_auth_clients=yes" && \
  postconf -e "smtpd_relay_restrictions=permit_sasl_authenticated,reject_unauth_destination" && \
  postconf -e "smtpd_sasl_security_options = noanonymous" && \
  echo 123456 | saslpasswd2 -c -p -u example.com postfix && \
  ln  /etc/sasldb2 /var/spool/postfix/etc/sasldb2 && \
  adduser postfix sasl && \
  touch /var/log/mail.log

COPY ./smtpd.conf /etc/postfix/sasl/smtpd.conf

CMD service rsyslog start && service postfix start && tail -f /var/log/mail.log

ln /etc/sasldb2 /var/spool/postfix/etc/sasldb2 По умолчанию postfix работет с файловой системой в «песочнице» /var/spool/postfix/. Там он будет искать файл с логинами /etc/sasldb2. Поэтому, задаем ссылку на файл /etc/sasldb2 из песочницы на реальный файл. Ссылка должны быть только жесткой (без параметра -s).

adduser postfix sasl вполне понятное и очень важно действие позволяет работать postfix с файлом /var/spool/postfix/etc/sasldb2.

Правило postconf -e "smtpd_recipient_restrictions=permit_sasl_authenticated,reject_unauth_destination" как раз и позволяет отправлять почту на произвольный домен всем прошедшим авторизацию sasl клиентам.

Конфигурация авторизации sasl в файле ./smtpd.conf:

log_level: 3
pwcheck_method: auxprop
auxprop_plugin: sasldb
mech_list: PLAIN LOGIN CRAM-MD5 DIGEST-MD5 NTLM

Параметр postconf -e "mydestination = localhost" говорит о том, что почту для этого домена не отправлять дальше а принимать на этом хосте. Как показывает опыт, почтовые сервера, которые должны принимать почту, очень часто настроены неверно, теряют почту. Иногда это критично т.к. может вредить бизнесу, если почтовое сообщение содержит заявку клиента на приобретение товара или услуги. Поэтому данная конфигурация настроена на отправку копии локальному получателю postconf -e "always_bcc = www-arc@localhost". Это получатель создается с идентификатором текущего пользователя useradd -u $UID www-arc.

Текущий пользователь определяется в конфигурации docker-compose:

  postfix:
    build:
      context: ./docker/postfix
      args:
       - UID
    volumes:
      - ./docker/postfix/mail:/var/mail

При билде текущий пользователь передается из окружения env UID=$UID docker-compose build.

Для подключения из другого контейнера docker к этому сервису, необходимо в качестве хоста указать postfix (название сервиса из docker-compose.yml), а имя с учетом домена (postfix@example.com) и пароль. Во всех случаях имя postfix не является обязательным инастраивается в конфигурации.

Настройка почты на стороне приложения и на строне почтового сервиса это еще даже не половина того что необходимо сделать. Все что нужно сделать еще кроме этого в настройках домена часто лежит вне контроля разработчика или девопса, а у некоего специалиста с правами редактироваить учетную запись домена. С которым приходится общаться по испорченному телефону. Пока будет проходить неторопливый диалог в стиле «эй, ребята, смотрите там у себя, это ваш бэк» — ваш ip-адрес попадет в черные списки разных почтовых сервисов, откуда исключить их будет ой как непросто. Поэтому есть смысл сразу воспользоваться услугами платных почтовых сервисов, например, docs.aws.amazon.com/ses/latest/DeveloperGuide/postfix.html. Интегрироваться с ними можно через API, но с моей точки зрения более надежно сделать это через postfix (он собственно для этого и предназначен), задав параметр relayhost = [email-smtp.us-west-2.amazonaws.com]:587. Более подробно интеграцию см. на сайте AWS (ссылка выше). Они как бы с одной стороны гарантируют непопадание вашего ip в черные списки а Вашей почты в спам, но зато сами могут объявить Вас спаммером в любой момент и заблокировать Вашу почту. Тоак что идельных решений не бывает.

Дополнение.

Конечно при решении задачи я «подглядывал» как это делают делают другие разработчики в открытых репозитариях и очень много почерпнул из этих источников. Поэтому разберу, как некоторые из конфигураций решают аналогичные задачи.

Для обзора я воспользовался ключевой фразой в поиске Google «docker sasl postfix». Поэтому, если кто-нибудь посоветует еще какие-то репозитарии, я из включу в этот список.

1) github.com/MarvAmBass/docker-versatile-postfix

Автор воспользовался не плагином postfix auxprop_plugin: sasldb, а стандартным средством sasl pwcheck_method: saslauthd. Это еще один дополнительный процесс который запускается в контейнере, и который не очень удобно конфигурировать, т.к. по умолчанию он выключен. Поэтому автор применяет в своей конфигурации такие вот конструкции:
RUN sed -i 's/^START=.*/START=yes/g' /etc/default/saslauthd; \
  sed -i 's/^MECHANISMS=.*/MECHANISMS="shadow"/g' /etc/default/saslauthd
RUN sed -i 's/^OPTIONS=/#OPTIONS=/g' /etc/default/saslauthd; \
  echo 'OPTIONS="-c -m /var/spool/postfix/var/run/saslauthd"' >> /etc/default/saslauthd


2) github.com/cloudposse/postfix

Аналогично предыдущему используется pwcheck_method: saslauthd

3) github.com/floriandejonckheere/docker-postfix

Автор использовал sasldb2 с плагином postfix, но отключил механизм «песочницы»: smtp inet n - n - - smtpd, и для запуска процессов использовал supervisor, таким образом включив в контейнер несколько процессов.

4) github.com/catatnight/docker-postfix
Подобно предыдущему, автор откючил «песочницу»: postconf -F '*/*/chroot = n' и использовал supervisor.

5) github.com/juanluisbaptiste/docker-postfix

Использует плоский файл с паролями: echo "[$SMTP_SERVER]:587 $SMTP_USERNAME:$SMTP_PASSWORD" >> /etc/postfix/sasl_passwd

6) github.com/container-images/postfix

Отключает песочницу sed -i 's/^smtp\(\s*\)inet\(.*\)/docker_smtp\1inet\tn\ty\tn\t-\t-\tsmtpd -v/g' "$MASTER"

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

Буду благодарен за дополнение этого списка репозитариев, и обещаю оперативно дополнять этот список по Вашим комментариям.

Список полезной литературы

1. Установка и настройка Docker + Docker Compose + Postfix + OpenDKIM на Debian в VScale для отправки e-mail с подписью. Vadim Khakulov. 7 декабрь 2016 г. 19:25

apapacy@gmail.com
8 апреля 2018 года
Tags:
Hubs:
+7
Comments15

Articles

Change theme settings