суббота, 27 сентября 2014 г.

Почтовый сервер: автоматический белый список

Какими бы либеральными ни были ограничения Postfix (smtpd_recipient_restrictions) в Zentyal, среди отправителей всегда найдется уникум, который под эти ограничения попадет, но принимать письма от которого все-таки нужно. Все еще более осложняется, если к "встроенным" ограничениям мы добавляем свои, как например в случае проверки SPF парой постов назад.
Идея автоматического белого списка заключается в том, чтобы адресаты почтовых сообщений посылаемых из нашего домена, не подвергались слишком строгим проверкам, когда они шлют нам ответ.
Предлагаемое решение является компиляцией из двух источников: проекта Рostpals и некого скрипта найденного в интернете. Оно позволяет автоматически заносить в белый список адреса получателей наших писем и обеспечивает обход ограничений Postfix для этих адресов. Также, за счет специального заголовка добавляемого в письма отправителей из белого списка, возможна настройка высокого уровня доверия к ним в прочих фильтрах (Amavis, SpamAssassin). Белый список автоматически очищается от устаревших записей, т. е. от тех адресатов, которым мы не посылали писем в течение определенного времени.

1) Создаем файл /etc/postfix/awl-prepend-header.pcre (root:root 644) следующего содержания:

/^/ PREPEND X-Auto-Whitelist-Hit: yes

[скачать готовый файл]
Это заголовок, который будет добавляться к письмам от адресатов из белого списка.

2)  Открываем файл /etc/zentyal/stubs/mail/main.cf.mas (почему у вас должен быть этот файл?), находим в нем фрагмент:

submission_recipient_restrictions = <% $submissionRecipientRestrictions %>
smtpd_restriction_classes = submission_recipient_restrictions

и приводим его к следующему виду (без переносов строк):

submission_recipient_restrictions = <% $submissionRecipientRestrictions %>
awl_prepend_header_and_permit = check_sender_access pcre:/etc/postfix/awl-prepend-header.pcre, permit_auth_destination
smtpd_restriction_classes = submission_recipient_restrictions, awl_prepend_header_and_permit


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

3) В веб-интерфейсе Zentyal заходим в настройки почтового сервера, делаем какое-нибудь незначительное изменение (например, меняем "Period for polling external mail accounts") и сохраняем настройки, чтобы  изменения сделанные в /etc/zentyal/stubs/mail/main.cf возымели действие.

4) Создаем скрипт  /usr/sbin/awl-parse-maillog (root:root 755) следующего содержания:

#!/usr/bin/perl

my %ids;

open LOGF, '/var/log/mail.log';

while (defined (my $line = <LOGF>)) {
  if ($line =~ /postfix\/(?:smtp|qmgr)\[[^\s]+(?:\s\[[^\]]*\])?\s(?<id>[0-9a-f]+):\s(?:(?<removed>r)emoved|from=<(?<from>[^>]+\@[^>]+)>|to=<(?<to>[^>]+\@[^>]+)>,\srelay=[^\[,]+\[((?!127\.)[\d.]+)\][^\(]+status=sent)/i) {
    if (defined $+{removed}) {
      delete $ids{$+{id}};
    } elsif (defined $+{from}) {
      $ids{$+{id}} = $+{from};
    } elsif (defined $ids{$+{id}}) {
      print lc($+{to}), "\n";
    }
  }
}

close LOGF;


[скачать готовый скрипт]
Этот скрипт находит в логе почты /var/log/mail.log адреса тех, кому посылали письма пользователи нашего домена.

5) Создаем скрипт /usr/sbin/awl-update-db (root:root 755) следующего содержания:

#! /bin/sh
#
# Postfix quick/dirty auto whitelisting script
# Cron this script to run as root once/twice a day. Usage w/ everything under smtpd_recipient_restrictions:
#
# smtpd_recipient_restrictions =
#        permit_mynetworks
#        permit_sasl_authenticated
#        reject_unauth_destination
#        check_sender_access hash:/etc/postfix/awl
#     ....
#
# grab all sent to addresses from the current mail log

/usr/sbin/awl-parse-maillog | sort -u > /var/log/awl.log

# merge the new addresses with the current list, eliminate dups
cat /var/log/awl.log /etc/postfix/awl.raw | sort -u > /tmp/awl.tmp

# keep a copy without action for next processing iteration
mv /tmp/awl.tmp /etc/postfix/awl.raw

# add action to each entry, generating new list file
sed 's/$/ awl_prepend_header_and_permit/g' /etc/postfix/awl.raw > /etc/postfix/awl

# regenerate hash
/usr/sbin/postmap /etc/postfix/awl

# cleanup
rm /etc/postfix/awl


[скачать готовый скрипт]
Этот скрипт принимает найденные адреса от /usr/sbin/awl-parse-maillog, сортирует, удаляет дубли и сохраняет в файл /var/log/awl.log. Таким образом, в /var/log/awl.log хранятся все адреса получателей наших писем найденные в текущем логе почты. Но, как известно, лог почты ротируется, поэтому далее скрипт смешивает данные из /var/log/awl.log с данными из файла /etc/postfix/awl.raw, в котором хранятся и адреса полученные из предыдущих логов. Результирующий список после сортировки и удаления дублей опять помещается в файл /etc/postfix/awl.raw.
Затем в промежуточном файле /etc/postfix/awl к каждому адресу списка добавляется действие awl_prepend_header_and_permit и postmap формирует из него таблицу поиска /etc/postfix/awl.db.

6) Открываем "Administrative console" на рабочем столе Zentyal и выполняем сначала touch /etc/postfix/awl.raw, а затем crontab -e. Далее выбираем редактор nano и добавляем строку:

*/10 9-17 * * * /usr/sbin/awl-update-db

в конец файла. Это периодический запуск /usr/sbin/awl-update-db через cron. Здесь */10 означает запуск каждые 10 минут, а 9-17 - часы дня, в которые будет работать скрипт (имейте ввиду, будет работать не до 17:00, а и в 17:10, 17:20 ... 17:50, т. е. до 18:00). Нет смысла гонять скрипт, когда все уже ушли с работы и не шлют никому писем. Закрываем редактор, сохранив файл под любым предложенным именем - crontab сам установит новое задание в /var/spool/cron/crontabs/root. Через некоторое время в каталоге /etc/postfix должен появиться файл awl.db, а файл /etc/postfix/awl.raw должен наполнится адресами наших получателей.

7)  Снова открываем файл /etc/zentyal/stubs/mail/main.cf, находим в нем строку:

$smtpRecipientRestrictions .= 'reject_unauth_destination, ';

сразу под ней вставляем строку:

$smtpRecipientRestrictions .= 'check_sender_access hash:/etc/postfix/awl, ';

и снова выполняем действия описанные в п. 3). Этим мы заставляем Postfix сверять отправителей с белым списком и применять к ним специальные ограничения.

8) Создаем файл /etc/logrotate.d/awl(root:root 644) следующего содержания:

/var/log/awl.log
{
    rotate 4
    weekly
    missingok
    notifempty
    lastaction
        cat /var/log/awl.log.* | sort -u > /etc/postfix/awl.raw
    endscript
}


[скачать готовый файл]
Это настройка ротации логов (/var/log/awl.log) белого списка, которая необходима для удаления из него устаревших, давно не использовавшихся записей.
Идея заключается в том, что при очередной ротации удаляется архив лога с самыми старыми записями и мы заново полностью пересобираем (см. команду в lastaction) актуальный белый список из оставшихся архивов лога, удалив таким образом из списка записи уникальные для ушедшего архива. Праметр "rotate 4" означает, что адрес продержится в списке минимум 4 недели, а максимум - 5 недель, если за это время мы снова не пошлем на него письмо. Этот параметр вы должны подобрать сами, из собственных соображений.

9) Открываем файл /var/lib/logrotate/status и вставляем в конец файла строку:

"/var/log/awl.log" 2014-9-21-7:31:0

где 2014-9-21-7:31:0 - дата и время прошлой ротации. Понятно, что никакой прошлой ротации еще не было, но нам необходимо дать logrotate точку отсчета. Поэтому просто берем эту дату и время из строки:

"/var/log/mail.log" 2014-9-21-7:31:0

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

На этом все. Настройка прочих почтовых фильтров (Amavis, SpamAssassin) выходит за рамки данной статьи (честно сказать, я использую Amavis только для антивируса, а SpamAssassin не использую вовсе). Напомню только, что в письмах от адресатов из белого списка присутствует заголовок:

X-Auto-Whitelist-Hit: yes

ориентируйтесь на него.

Дополнено: Снова об AWL

Комментариев нет:

Отправить комментарий