Configuring Linux
System administration
September 2013 13

Я построю свой почтовый сервер с Postfix и Dovecot

Tutorial
image

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

Мануал пошаговый, основывается на внутренней документации компании и затрагивает совершенно очевидные вопросы. Гуру могут не тратить время, ноу-хау здесь нет – руководство является сборной солянкой и публикуется только потому, что все найденные руководства по развёртыванию почтовика напоминали картинку о том, как рисовать сову.

Для тех, кто не хочет собирать всё вручную, оптимальным вариантом, пожалуй, будет пакет iRedMail. Отличная сборка Postfix, Dovecot, Apache, MySQL/PostgreSQL, Policyd, Amavis, Fail2ban, Roundcube и даже Awstats. Ставится легко, работает стабильно, есть красивая админка (бесплатная) и очень красивая админка (платная) не идущая ни в какое сравнение с убогим PostfixAdmin. Поклонники же ручного труда могут продолжить чтение.

Старый сервер работал под Gentoo и нёс в себе термоядерный заряд из Postfix+VDA с Courier и глючно реализованного SASL, решавшим подключаться к mysql только при первой аутентификации. План переделки заключался в миграции на наш внутренний стандарт – CentOS. Роль MTA и MDA возлагается на связку Postfix и Dovecot, а в качестве вспомогательной артиллерии: Amavis + SpamAssassin + ClamAV + Postgrey + Fail2Ban. Письма хранятся в файлах, а учётные записи и домены — в MySQL. На сервере крутится несколько почтовых доменов и есть поддержка виртуальных квот.




image

[*] Подключаем дополнительные репозитории. Мне хватило epel, rpmforge, centalt и remi. Не все они нужны постоянно включёнными, и можно установить плагин yum-priorities; ну или если лень разбираться, то включать-отключать их руками. Далее я буду говорить, что из какого репозитория устанавливается.

[*] Работа с SELinux достойна отдельного материала, поэтому в рамках данной статьи примем, что selinux по-ламерски сделан permissive или disabled.

[*] Не забываем про ntp:
yum install ntp
ntpdate <ваш ntp сервер>
chkconfig ntpd on && /etc/init.d/ntpd start

Это позволит избежать возможной проблемы Dovecot’a «Time has moved backwards». Также можно в /etc/sysconfig/ntpd изменить ключ на -L, чтобы ntpd не слушал сеть.

[*] В завершение подготовительного этапа ставим утилиты, которые облегчат нам тестирование и дальнейшую работу:
yum install wget mlocate bind-utils telnet mailx sharutils




image

Для нашей базы данных используем MySQL 5.5 от Remi. Можно и mariadb, конечно, но пока MySQL ещё жив, вышеупомянутая сборка меня полностью устраивает. Версия важна, т.к. при обновлении Postfix до 2.10 он захочет новую версию и если поставить 5.1 из base, то обновление постфикса из CentALT потянет за собой MariaDB. Кому больше нравится PgSQL — пожалуйста, ставьте его. Развёртывание ничем отличаться не будет, даже конфигурационные файлы postfix можно будет брать неизменными. Отличаться будет только настройка самого postgresql и создание базы.

Для запуска подойдёт вариант «из коробки» (в репозитории ниже представлен слегка расширенный my.cnf). Создаём пользователя postfix с одноимённой базой и всеми правами на неё.
CREATE USER postfix@localhost IDENTIFIED BY 'mypassword';
CREATE DATABASE postfix;
GRANT ALL PRIVILEGES ON postfix.* TO postfix;


Антивирусом у меня работает ClamAV. Стоит отметить, что самая последняя версия есть на CentALT, однако она в упор не хочет оттуда скачиваться, умирая на попытке скачать 50 мегабайт clamav-db. Поэтому ставим из EPEL на пару минорных версий меньше, погоды это не сделает. Clam будет работать у нас через сокет, поэтому в /etc/clamd.conf комментируем строки:
#TCPSocket 3310
#TCPAddr 127.0.0.1

Обновление баз антивируса подключается автоматически, за него отвечает утилита freshclam. Проконтролируем, чтобы соответствующий файл находился в cron.daily и запускаем сервис антивируса
freshclam
chkconfig clamd on && /etc/init.d/clamd start




image

Развёртывать или не развёртывать веб-интерфейс — личное дело каждого. Мне он понадобился для контроля процесса миграции. Вам он может понадобиться для создания структуры базы и администрирования доменов, ящиков, алиасов и т.п. Для последних задач в большинстве руководств активно предлагается PostfixAdmin, но мне он категорически не нравится. Равно как я бы рекомендовал придерживаться принципа разделения, по которому почтовый сервер должен заниматься обработкой почты, веб-сервер держать веб-приложения, а DB-сервер работать с базами данных.

Для тех, кто не захочет развёртывать веб-подсистему, прилагаю SQL-дамп базы данных для почтового сервера на все случаи жизни. Даже с некоторыми неиспользуемыми возможностями: mysql_dump.sql на гитхабе.

Если же потребуется PostfixAdmin — ставьте nginx/apache + php и собственно сам PostfixAdmin. И обратите внимание, что развернуть его поверх приведённого дампа не удастся — из структуры удалены некоторые «лишние» таблицы. Нюансов настройки PostfixAdmin немного. Редактируем config.inc.php, обращая внимание на следующие параметры:
## должен содержать тот же метод хэширования пароля, что и dovecot
$CONF['encrypt'] = 'md5crypt';
$CONF['transport_default'] = 'virtual';
$CONF['emailcheck_resolve_domain']='NO';
## Поскольку будет использоваться dovecot, убираем префикс
$CONF['create_mailbox_subdirs_prefix']='';
## На случай, если захочется использовать хранение квот не в maildir, а в базе данных через dict
$CONF['new_quota_table'] = 'yes';

После этого можно идти на domain.tld/postfixadmin/setup.php, генерировать пароль и создавать учётную запись супер-администратора. Теперь сгенерированный хэш надо внести в файл config.inc.php и изменить его статус:
$CONF['configured'] = true;
$CONF['setup_password'] = 't8h9i9s2i7s7m2y4l9o8g9i4n:a0n9d5p2a5s2s9w5o4r7d';

[!] Postfixadmin сам создаёт структуру базы и в mysql, и в postgresql при запуске setup.php. Если намереваетесь использовать его, установку следует проводить на пустую базу.




image

Проконтролируем, что в базе postfix создана вся дефолтная структура и перейдём к установке MTA и MDA. Postfix уже идёт в комплекте с CentOS, но не самый новый. Обновим его из CentALT и оттуда же поставим Dovecot.
yum update postfix
yum install dovecot dovecot-mysql


Все основные системы корабля будут оперировать с файлами в /var/vmail под отдельным юзверем:
groupadd  -g 1000 vmail
useradd -d /var/vmail/ -g 1000 -u 1000 vmail
chown vmail:vmail /var/vmail


Сделаем самоподписанные SSL'ки
mkdir /etc/postfix/certs
openssl req -new -x509 -days 3650 -nodes -out /etc/postfix/certs/cert.pem -keyout /etc/postfix/certs/key.pem


Самый противный этап сборки – убедить Postfix работать с базой данных:
mkdir /etc/postfix/mysql

В этой директории создаём файлы со следующим содержанием:
Конфигурация postfix mysql
relay_domains.cf
hosts = localhost
user = postfix
password = mypassword
dbname = postfix
query = SELECT domain FROM domain WHERE domain='%s' and backupmx = '1'


virtual_alias_domain_maps.cf
hosts = localhost
user = postfix
password = mypassword
dbname = postfix
query = SELECT goto FROM alias,alias_domain WHERE alias_domain.alias_domain = '%d' and alias.address = CONCAT('%u', '@', alias_domain.target_domain) AND alias.active = 1


virtual_alias_maps.cf
hosts = localhost
user = postfix
password = mypassword
dbname = postfix
query = SELECT goto FROM alias WHERE address='%s' AND active = '1'


virtual_mailbox_domains.cf
hosts = localhost
user = postfix
password = mypassword
dbname = postfix
query = SELECT domain FROM domain WHERE domain='%s' AND backupmx = '0' AND active = '1'


virtual_mailbox_maps.cf
hosts = localhost
user = postfix
password = mypassword
dbname = postfix
query = SELECT maildir FROM mailbox WHERE username='%s' AND active = '1'



Редактируем файл /etc/postfix/main.cf, обучая Postfix работать с базой по свежесозданным файлам:
# ============================================================
# MySQL mappings
# ============================================================
relay_domains = mysql:/etc/postfix/mysql/relay_domains.cf
virtual_alias_maps = mysql:/etc/postfix/mysql/virtual_alias_maps.cf,
                     mysql:/etc/postfix/mysql/virtual_alias_domain_maps.cf
virtual_mailbox_domains = mysql:/etc/postfix/mysql/virtual_mailbox_domains.cf
virtual_mailbox_maps = mysql:/etc/postfix/mysql/virtual_mailbox_maps.cf


Хороший почтовый сервер пропускает своих и авторизует чужих. Чтобы аутентификация работала корректно, запустим Submission, подняв SMTP сервис дополнительно на 587 порту. Смартфоны при создании новых учётных записей при вписывании smtp сервера с аутентификацией по умолчанию предлагают 587 порт; вы же не хотите объяснять клиентам, что недостаточно вписать mail.domain.tld, а ещё надо и порты какие-то прописывать. В общем, в /etc/postfix/master.cf редактируем секцию, отвечающую за submission:
submission inet n       -       n       -       -       smtpd
  -o syslog_name=postfix/submission
  -o smtpd_tls_wrappermode=no
  -o smtpd_tls_security_level=encrypt
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_recipient_restrictions=permit_mynetworks,permit_sasl_authenticated,reject
  -o smtpd_relay_restrictions=permit_mynetworks,permit_sasl_authenticated,defer_unauth_destination
  -o milter_macro_daemon_name=ORIGINATING

[!] Обязательно обращаем внимание на пробелы перед -o ключами — без них конфиг не будет валидным.

Пока отложим в сторону master.cf, к нему мы вернёмся позднее, и продолжим с /etc/postfix/main.cf
soft_bounce = no
myhostname = mail.domain.tld
mydomain = domain.tld
myorigin = $myhostname

# Убираем $myhostname и $mydomain из локального класа
# Чтобы не было do not list domain in BOTH mydestination and virtual_mailbox_domains
mydestination = localhost.$mydomain, localhost

## Вписываем свои сетки
## Обязательно отредактировать и сузить до максимально узкого диапазона
## Лучше вообще не использовать и не позволять отправку почты без авторизации
mynetworks = 192.168.0.0/16, 127.0.0.0/8

## Убираем nis:/ чтобы избежать спама в лог 
## dict_nis_init: NIS domain name not set - NIS lookups disabled
alias_maps = hash:/etc/aliases

smtpd_banner = $myhostname ESMTP $mail_name
debug_peer_level = 2
debug_peer_list = 127.0.0.1


Это были изменения строк по умолчанию. А теперь добавим несколько секций наших настроек. Проверьте на дубликаты, убирая их из родной конфигурации, если они там встречаются. Я предлагаю свои настройки вписывать структурированными блоками в нижней части файла /etc/postfix/main.cf:
Очередная конфигурационная простыня
# ============================================================
# RESTRICTIONS
#
# Uncomment reject_rbl_client if necessary
# More information at: http://help.ubuntu.ru/wiki/фильтрация_спама_на_уровне_smtp_протокола
# ============================================================
smtpd_discard_ehlo_keywords = etrn, silent-discard
smtpd_forbidden_commands = CONNECT GET POST
broken_sasl_auth_clients = yes
smtpd_delay_reject = yes
smtpd_helo_required = yes
disable_vrfy_command = yes

smtpd_helo_restrictions = permit_mynetworks,
                          permit_sasl_authenticated,
                          reject_non_fqdn_helo_hostname,
                          reject_invalid_helo_hostname

smtpd_data_restrictions = permit_mynetworks,
                          permit_sasl_authenticated,
                          reject_unauth_pipelining,
                          reject_multi_recipient_bounce,

smtpd_sender_restrictions = permit_mynetworks,
                            permit_sasl_authenticated,
                            reject_non_fqdn_sender,
                            reject_unknown_sender_domain

smtpd_recipient_restrictions = reject_non_fqdn_recipient,
                               reject_unknown_recipient_domain,
                               reject_multi_recipient_bounce,
                               permit_mynetworks,
                               permit_sasl_authenticated,
                               reject_unauth_destination,
                               check_policy_service unix:/var/spool/postfix/postgrey/socket,
                               #reject_rbl_client zen.spamhaus.org,
                               #reject_rbl_client bl.spamcop.net,
                               #reject_rbl_client dnsbl.sorbs.net,
                               reject_invalid_hostname

# ============================================================
# TLS
# ============================================================
smtp_tls_security_level = may
smtpd_tls_security_level = may
smtpd_tls_loglevel = 1
smtpd_tls_received_header = yes
smtpd_tls_session_cache_timeout = 3600s
smtp_tls_session_cache_database = btree:$data_directory/smtp_tls_session_cache
smtpd_tls_key_file = /etc/postfix/certs/key.pem
smtpd_tls_cert_file = /etc/postfix/certs/cert.pem
tls_random_source = dev:/dev/urandom

# ============================================================
# LIMITS
# ============================================================
message_size_limit = 51200000
smtpd_soft_error_limit = 10
smtpd_hard_error_limit = 15
smtpd_error_sleep_time = 20
anvil_rate_time_unit = 60s
smtpd_client_connection_count_limit = 20
smtpd_client_connection_rate_limit = 30
smtpd_client_message_rate_limit = 30
smtpd_client_event_limit_exceptions = 127.0.0.1/8
smtpd_client_connection_limit_exceptions = 127.0.0.1/8

# ============================================================
# QUEUE
# ============================================================
maximal_queue_lifetime = 1d
bounce_queue_lifetime = 1d


[!] Использовать или не использовать чёрные списки — ваш выбор. Я закомментировал соответствующие директивы reject_rbl_client, чтобы не плодить холивары. Грейлистинга зачастую хватает, а Spamhaus и иже с ним исповедуют неоднозначную политику, но на практике оказалось, что «честных ребят», в чёрные списки просто так не заносит и ложных срабатываний у нас не было. Повезло, наверное. Поэтому — дело вкуса включать директивы RBL или нет. Считайте, что я их указал в информационных целях.
[!] Параметры разбиты по группам — внимательно пересмотрите их и подстройте под собственные нужды. Хуже нет варианта, чем вслепую влепить чужой конфиг без правок.
[!] Malamut справедливо заметил, что опция `permit_mynetworks` крайне сомнительна и опасна. Гораздо лучше будет её убрать и разрешать отправку корреспонденции только пользователям, прошедшим аутентификацию.
[!] К файлу main.cf мы снова вернёмся, добавляя в него postgrey, amavis и dovecot, а пока перейдем к MDA




image

Что это такое:
  • Это наш Mail Delivery Agent, локальный транспорт
  • Собственный SASL, через который будет работать Postfix
  • Работа с квотами
  • Предоставление пользователю imap и pop3


Пара изменений в /etc/dovecot/dovecot.conf:
protocols = imap pop3
login_greeting = Hello there.

Остальная часть конфигурационного файла удобно разбита на составляющие и прекрасно документирована:
10-auth.conf
disable_plaintext_auth = no
auth_realms = domain.tld domain2.tld
auth_default_realm = domain.tld
auth_mechanisms = plain login
## [!] Комментируем auth-system.conf.ext, чтобы не 
## заставлять dovecot искать пользователя в pam
#!include auth-system.conf.ext


10-logging.conf
Отдельного перечисления не будет — по желанию включаем нужные опции.

10-mail.conf
mail_location = maildir:/var/vmail/%d/%n
mail_uid = 1000
mail_gid = 1000
mail_plugins = quota

10-master.conf
# Поднимаем imap и imaps
service imap-login {
  inet_listener imap {
    port = 143
  }
  inet_listener imaps {
    port = 993
    ssl = yes
  }
}

# Поднимаем pop3 и pop3s
service pop3-login {
  inet_listener pop3 {
    port = 110
  }
  inet_listener pop3s {
    port = 995
    ssl = yes
  }
}

# Поднимаем SASL, куда будет ходить postfix
service auth {
  unix_listener auth-userdb {
    mode = 0600
    user = vmail
    group = vmail
  }
  unix_listener /var/spool/postfix/private/auth {
    mode = 0666
    user=postfix
    group=postfix
  }
}


10-ssl.conf
ssl = yes
ssl_cert = </etc/postfix/certs/cert.pem
ssl_key = </etc/postfix/certs/key.pem

15-lda.conf
quota_full_tempfail = no
lda_mailbox_autocreate = yes
lda_mailbox_autosubscribe = yes
protocol lda {
mail_plugins = $mail_plugins autocreate
}

20-imap.conf
protocol imap {
mail_plugins = $mail_plugins autocreate quota imap_quota
}

90-plugin.conf
# Данные для вас могут отличаться.
# Такие папки создавались для безболезненной миграции со старой системы
plugin {
  autocreate = Trash
  autocreate2 = sent-mail
  autocreate3 = drafts
  autosubscribe = Trash
  autosubscribe2 = sent-mail
  autosubscribe3 = drafts
}


90-quota.conf
# Отредактируйте значения в соответствии с собственными нуждами.
plugin {
  quota_rule = *:storage=200M
  quota_rule2 = Trash:storage=+10M
}

plugin {
  quota_warning = storage=90%% quota-warning 90 %u
}

# Проверьте, чтобы у скрипта был нужный chmod
# Плюс чтобы в quota-warning.sh был указан корректный путь до dovecot-lda
service quota-warning {
  executable = script /usr/local/bin/quota-warning.sh
  user = vmail
  unix_listener quota-warning {
    user = vmail
  }
}

# Формат хранения квоты - maildir
# При желании можно менять на dict, fs или dirsize
# Подробная документация в http://wiki2.dovecot.org/Quota
plugin {
  quota = maildir:User quota
}


auth-sql.conf.ext
passdb {
driver = sql
args = /etc/dovecot/dovecot-sql.conf.ext
}
userdb {
driver = sql
args = /etc/dovecot/dovecot-sql.conf.ext
}


Создаём /etc/dovecot/dovecot-sql.conf.ext:
dovecot-sql.conf.ext
driver = mysql
connect = host=localhost dbname=postfix user=postfix password=mypassword
default_pass_scheme = MD5-CRYPT
user_query = SELECT '/var/vmail/%d/%n' as home, 'maildir:/var/vmail/%d/%n'as mail, 1000 AS uid, 1000 AS gid, concat('*:bytes=', quota) AS quota_rule FROM mailbox WHERE username = '%u' AND active = '1'
password_query = SELECT username as user, password, '/var/vmail/%d/%n' as userdb_home, 'maildir:/var/vmail/%d/%n' as userdb_mail, 1000 as userdb_uid, 1000 as userdb_gid, concat('*:bytes=', quota) AS userdb_quota_rule FROM mailbox WHER
E username = '%u' AND active = '1'


Теперь подружим Postfix с Dovecot. Добавим две секции в /etc/postfix/main.cf:
# ============================================================
# SASL
# ============================================================
smtpd_sasl_auth_enable = yes
smtpd_sasl_security_options = noanonymous
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth

# ============================================================
# VIRTUAL
# ============================================================
virtual_mailbox_base = /var/vmail
virtual_minimum_uid = 1000
virtual_uid_maps = static:1000
virtual_gid_maps = static:1000
virtual_transport = dovecot
dovecot_destination_recipient_limit = 1


И поставим Postfix перед фактом, что доставкой почты занимается dovecot. В /etc/postfix/master.cf:
# ====================================================================
# DOVECOT
# ====================================================================
dovecot unix    -       n       n       -       -      pipe
  flags=DRhu user=vmail:vmail argv=/usr/libexec/dovecot/deliver -f ${sender} -d ${recipient}


Далее необходимо проконтролировать, чтобы скрипт предупреждения о превышении квоты /usr/local/bin/quota-warning.sh отрабатывал корректно. В моём случае в CentOS путь в нём был указан неверно и пришлось править его вручную. Его в любом случае, кстати, поправить вручную, отредактировав адрес отправителя, который по умолчанию указан, как postmaster@domain.tld. Найдём искомый бинарник
updatedb
locate dovecot-lda
chmod 755 /usr/local/bin/quota-warning.sh

И поправим путь в самом /usr/local/bin/quota-warning.sh, при желании добавляя в скрипт более содержательные заголовки.




image

Поскольку у нас будет работать Amavis, который является прослойкой между почтовыми агентами и антивирусно-антиспамовыми системами, то запускать spamd отдельно не нужно – он работает как модуль, подгружающийся при необходимости. Чтобы SA держать обновлённым, используется родная утилита sa-update. Убедимся, что в etc/cron.d есть файлик sa-update с запланированным запуском апдейтера.

[!] Ставьте spamassassin 3.3.2 из rpmforge-extras, т.к. втыкающаяся из EPEL версия 3.3.1 имеет врождённый дефект в sa-update. Последняя версия 3.3.2 уже избавлена от этой проблемы и обновляется корректно
yum install spamassassin amavisd-new

Немного подкорректируем /etc/mail/spamassassin/local.cf
local.cf
required_hits 6
report_safe 0
rewrite_header Subject ***SPAM***

#
# WEIRD STUFF
#
score FORGED_MUA_OUTLOOK 2.199 2.199 0.963 1.116
score FH_DATE_PAST_20XX 0.0
score DOS_OE_TO_MX_IMAGE 0.0
score DOS_OE_TO_MX 0.0
score DOS_OUTLOOK_TO_MX 0.0
score TO_NO_BRKTS_DIRECT 0.0
score HELO_LOCALHOST 0.0
score FSL_RU_URL 0.0
score FROM_MISSP_EH_MATCH 1.0
score TVD_RCVD_SINGLE 1.0
score TO_IN_SUBJ 1.0

#
# TUNING
#
score SUBJ_FULL_OF_8BITS 0.00
score HTML_COMMENT_8BITS 0.01
score HEADER_8BITS 0.00
score TO_NO_USER 0.01
score FORGED_MUA_OUTLOOK 0.5
score X_AUTH_WARNING 0.01
score SUBJ_HAS_UNIQ_ID 9.99
score HTTP_USERNAME_USED 9.99
score FORGED_YAHOO_RCVD 9.99
score FORGED_JUNO_RCVD 16
score UNWANTED_LANGUAGE_BODY 1.02
score MLM 5.55
score RCVD_NUMERIC_HELO 4.95

#
# WHITE/BLACK LISTS
#
whitelist_from root@localhost
whitelist_from *@example.com
blacklist_from *@outblaze.com
auto_whitelist_path /etc/mail/spamassassin/auto-whitelist
auto_whitelist_file_mode 0666



А вот конфигурационный файл Amavis'а — полная противоположность расхваливаемым мною конфигам Dovecot. Он представляет собой обычный perl скрипт, который к тому же ещё и плохо форматирован. Я вношу изменения просто — переименовываю файл в .pl и редактирую с подсветкой синтаксиса; это хоть немного облегчает жизнь.
amavisd.conf
# количество экземпляров amavisd
# должно совпадать с указанным в /etc/postfix/master.cf
$max_servers = 4;

# Домен по умолчанию
$mydomain = 'domain.tld';

# Правим доверенные подсетки
@mynetworks = qw( 127.0.0.0/8 [::1] [FE80::]/10 [FEC0::]/10
                  10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 );

# Твик для 2.6.4 и старше. Избавляемся от предупреждения в логе 
# Open relay? Nonlocal recips but not originating
@client_ipaddr_policy = map { $_ => 'MYNETS' } @mynetworks;

# Переписываем пороговые значения для spamassassin
$sa_tag_level_deflt  = 2.0;
$sa_tag2_level_deflt = 5.2;
$sa_kill_level_deflt = 6.5;
$sa_dsn_cutoff_level = 10; 

# Куда будут отправляться уведомления о письмах с вирусами и спамом
$virus_admin               = "virusalert\@$mydomain";
$mailfrom_notify_admin     = "virusalert\@$mydomain";
$mailfrom_notify_recip     = "virusalert\@$mydomain";
$mailfrom_notify_spamadmin = "abuse\@$mydomain";     

# Обязательно указываем имя хоста сервера
$myhostname = 'mail.domain.tld'; 

# Что делать при срабатывании
$final_virus_destiny      = D_DISCARD;
$final_banned_destiny     = D_BOUNCE;
$final_spam_destiny       = D_DISCARD;
$final_bad_header_destiny = D_PASS;

# Если будем использовать карантин, то указываем куда карантинить
# Разумеется, соответствующие почтовые ящики должны существовать
$virus_quarantine_to = "virus-quarantine\@$mydomain";
$spam_quarantine_to  = "spamtrap\@$mydomain";

# Если надо какие-то адреса или домены внести в белый список
# создаём массив
@whitelist_sender_maps = ( new_RE(
    qr'.*@example\.com$'i,
    qr'user@test\.org$'i,
));

# Весь массив @av_scanners сокращаем до
@av_scanners = (
  ['ClamAV-clamd',
    \&ask_daemon, ["CONTSCAN {}\n", "/var/run/clamav/clamd.sock"],
    qr/\bOK$/m, qr/\bFOUND$/m,
    qr/^.*?: (?!Infected Archive)(.*) FOUND$/m ],
);

);

# И второй тоже
@av_scanners_backup = (
  ['ClamAV-clamscan', 'clamscan',
  "--stdout --no-summary -r --tempdir=$TEMPBASE {}",
  [0], qr/:.*\sFOUND$/m, qr/^.*?: (?!Infected Archive)(.*) FOUND$/m ],
);


Теперь сообщим Postfix'у, что отныне он использует Amavis для проверки почты. Вносим соответствующий блок в /etc/postfix/master.cf
master.cf
# ====================================================================
# AMAVIS
# ====================================================================
amavisfeed unix -       -       n       -       4       lmtp
  -o lmtp_data_done_timeout=1200
  -o lmtp_send_xforward_command=yes
  -o disable_dns_lookups=yes
  -o max_use=20
127.0.0.1:10025 inet n    -       n       -       -     smtpd
  -o content_filter=
  -o smtpd_delay_reject=no
  -o smtpd_client_restrictions=permit_mynetworks,reject
  -o smtpd_helo_restrictions=
  -o smtpd_sender_restrictions=
  -o smtpd_recipient_restrictions=permit_mynetworks,reject
  -o smtpd_data_restrictions=reject_unauth_pipelining
  -o smtpd_end_of_data_restrictions=
  -o smtpd_restriction_classes=
  -o mynetworks=127.0.0.0/8,192.168.0.0/16
  -o smtpd_error_sleep_time=0
  -o smtpd_soft_error_limit=1001
  -o smtpd_hard_error_limit=1000
  -o smtpd_client_connection_count_limit=0
  -o smtpd_client_connection_rate_limit=0
  -o receive_override_options=no_header_body_checks,no_unknown_recipient_checks,no_milters,no_address_mappings
  -o local_header_rewrite_clients=
  -o smtpd_milters=
  -o local_recipient_maps=
  -o relay_recipient_maps=


и в /etc/postfix/main.cf добавляем
# ============================================================
# AMAVIS
# ============================================================
content_filter=amavisfeed:[127.0.0.1]:10024

Отрабатываем сервисы:
chkconfig amavisd on && /etc/init.d/amavisd start
/etc/init.d/postfix restart

telnet 127.0.0.1 10024
# 220 [127.0.0.1] ESMTP amavisd-new service ready





image

Об эффективности грейлистинга писалось уже не раз, поэтому просто молча
yum install postgrey


Никакой дополнительной конфигурации не требуется — прописываем его в /etc/postfix/main.cf
smtpd_recipient_restrictions = ...
                               reject_unauth_destination,
                               check_policy_service unix:/var/spool/postfix/postgrey/socket,
                               ...

[!] Директива check_policy_service должна обязательно идти после reject_unauth_destination.
Если есть необходимость исключить из проверки какие-либо сервера — редактируем /etc/postfix/postgrey_whitelist_clients.local, а для исключения из проверки конкретные почтовые адреса на локальном сервере — редактируем postgrey_whitelist_recipients. Исчерпывающая информация доступна в вики: wiki.centos.org/HowTos/postgrey

Про Fail2ban разговор отдельный. Чтобы продемонстрировать его эффективность, покажу картинку со статистикой почтового сервера до и после установки утилиты. Красная линия на графике – неавторизованная долбёжка в поисках открытого релея. Письма, конечно, отсекаются, да и нагрузку большую не создают, но зачем вообще слушать этот мусор. Поэтому установка fail2ban с тремя правилами значительно улучшают внешний вид графика:


yum install fail2ban

Правила для почтового сервера /etc/fail2ban/jail.conf
# Тут оставляем и редактируем общие
# правила, игнорируемые подсетки
# и политику партии

##
## Убедитесь, что путь к логам соответствует действительности
##

[ssh-iptables]
enabled  = true
filter   = sshd
action   = iptables[name=SSH, port=ssh, protocol=tcp]
logpath  = /var/log/secure
maxretry = 5

[postfix-banhammer]
enabled  = true
filter   = postfix
action   = iptables-multiport-tcp[name=PFIX, port="smtp,smtps", protocol=tcp]
logpath  = /var/log/maillog
maxretry = 3
bantime  = 7200

[dovecot-banhammer]
enabled  = true
filter   = dovecot
action   = iptables-multiport-tcp[name=DCOT, port="pop3,pop3s,imap,imaps", protocol=tcp]
logpath  = /var/log/maillog
findtime = 300
maxretry = 10
bantime  = 1800

[sasl-banhammer]
enabled  = true
filter   = sasl
action   = iptables-multiport-tcp[name=SASL, port="smtp,smtps", protocol=tcp]
logpath  = /var/log/maillog
findtime = 300
maxretry = 10
bantime  = 1800


Если SSH открыт только на внутреннюю сеть, то первое правило можно и убрать. И всё, никаких дополнительных телодвижений – правила работают «из коробки». Спасибо urbain за напоминание о защите от перебора smtp.
chkconfig fail2ban on && /etc/init.d/fail2ban start




image

Поскольку в Dovecot мы подключили плагин autocreate, то для создания доменов и почтовых ящиков достаточно завести их в базу через Postfixadmin или делая INSERT INTO в консоли. При первой же аутентификации или первом полученном письме структура директорий будет создана автоматически.

Потестируем pop3, imap, smtp в разных позах
  1. Тестируем логин POP3
    telnet 127.0.0.1 110
    user test
    pass testpassword
    UIDL
    

  2. Тестируем логин IMAP
    telnet 127.0.0.1 143
    1 LOGIN test testpassword
    1 SELECT INBOX
    

  3. Тестируем SMTP без авторизации
    telnet 127.0.0.1 25
    #220 mail.domain.tld ESMTP Postfix
    helo darling
    #250 mail.domain.tld
    MAIL FROM: root@localhost
    #250 2.1.0 Ok
    RCPT TO: test@example.com
    #250 2.1.5 Ok
    DATA
    #354 End data with <CR><LF>.<CR><LF>
    this is text message
    
    .
    #250 2.0.0 Ok: queued as E3BA1A15FA
    quit
    #221 2.0.0 Bye
    

  4. Тестируем SMTP c авторизацией без SSL
    Предварительно закодируйте в base64 тестовые логин и пароль, которые посылаются последовательно после AUTH LOGIN. Входящие требования с кодом 334 тоже закодированы в base64.
    telnet 127.0.0.1 25
    #220 mail.domain.tld ESMTP Postfix
    ehlo darling
    #250-mail2.dautkom.lv
    #250-PIPELINING
    #250-SIZE 51200000
    #250-STARTTLS
    #250-AUTH PLAIN LOGIN
    #250-AUTH=PLAIN LOGIN
    #250-ENHANCEDSTATUSCODES
    #250-8BITMIME
    #250 DSN
    AUTH LOGIN
    #334 VXNlcm5hbWU6
    dGVzdA==
    #334 UGFzc3dvcmQ6
    dGVzdHBhc3N3b3Jk
    #235 2.7.0 Authentication successful
    

  5. Тестируем SMTP c SSL
    # Зашифруем наши credentials
    perl -MMIME::Base64 -e 'print encode_base64("\000test\@example.com\000testpassword")'           
    # Получаем строку 
    # AHRlc3RAZXhhbXBsZS5jb20AdGVzdHBhc3N3b3Jk
    
    openssl s_client -starttls smtp -connect 127.0.0.1:587 -crlf -ign_eof
    # Обмен приветствиям
    # На полтора экрана текста
    
    EHLO darling
    #250-mail.example.com
    #250-PIPELINING
    #250-SIZE 51200000
    #250-ENHANCEDSTATUSCODES
    #250-8BITMIME
    #250 DSN
    
    AUTH PLAIN AHRlc3RAZXhhbXBsZS5jb20AdGVzdHBhc3N3b3Jk
    #235 2.7.0 Authentication successful
    



Потестируем антивирусную защиту
  1. В комплекте с amavis идут вирусы и спам. Тестовые, разумеется. И чтобы сканеры не паниковали, они лежат запакованные. Поэтому перед дальнейшими тестами распакуем эту радость:
    cd /usr/share/doc/amavisd-new-2.8.0/test-messages
    perl -pe 's/./chr(ord($&)^255)/sge' <sample.tar.gz.compl | zcat | tar xvf -
    


  2. Теперь можно тестировать отправку вирусов и спама:
    sendmail -i your-address@example.com < sample-virus-simple.txt
    sendmail -i your-address@example.com < sample-spam-GTUBE-junk.txt
    

    Информацию по обработке можно читать в логах (по умолчанию /var/log/maillog). Чтобы увидеть больше информации, поднимите уровень verbose в /etc/dovecot/conf.d/10-logging.conf и log-level в /etc/amavisd/amavisd.conf.





image

Теперь питание компьютера можно отключить можно начинать работать с почтовым сервером, создавать домены, пользователей, алиасы и т.п. Напоследок несколько общих моментов и рекомендаций:

  1. Для работы с конфигурационными файлами я использую git, превратив директорию /etc в репозиторий. Такой подход позволяет удобно шарить конфиги между сотрудниками техотдела и пошагово контролировать процесс настройки. В работе с такой комплексной системой, как почтовый сервер, подобная практика может сильно облегчить жизнь.
  2. Одной из моих задач была миграция c courier на dovecot. И да, это реально. Официальная документация wiki2.dovecot.org/Migration/Courier даёт почти всю необходимую информацию. В дополнение к ней порекомендую вручную выполнить POP3 команду UIDL на старом и новом сервере под одним и тем же пользователем с непустым почтовым ящиком, сравнивая результаты. Они должны быть одинаковыми, иначе почтовый клиент пользователя скачает всю почту из ящика заново.
    Также можно по окончании миграции на новом сервере удалить ненужные папки и файлы
    find . -name "courier*" -delete
    
  3. Не забудьте про iptables — откройте только нужные порты и скройте от любопытных глаз служебные.
  4. Идущий в комплекте с CentOS логгер rsyslog мне никогда не нравился, и я его меняю на syslog-ng из EPEL. Кстати, при непосредственном участии syslog-ng рисуется график из шестой главы — сбор и запись статистики ведётся путём парсинга логов.
  5. Таблица vacation создаётся, но в dovecot не поставлен плагин Sieve и «автоответчика» нет. Поэтому таблица — просто задел «на будущее». Гайд и так гигантский получился.


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

Ещё раз подчеркну, что это начальный этап установки. Даже если не считать подключение мониторинга, который крайне желателен на почтовом сервере, работы ещё непочатый край. Однозначно потребуется тщательная настройка антиспам политики; если планируется использовать дополнительные релеи, то потребуется доработка запросов; обязательно будет нужно выверять параметры ограничений и т.п.

Но в остальном на этом пробу пера в написании масштабного руководства можно считать завершённой. В планах есть публикация материала уже не для «начинающих» и не по почтовому серверу, но я решил потренироваться на кошках. Кто дочитал до этого места… гм… завидую вашему терпению, но разбивать публикацию на несколько частей представлялось нецелесообразным.
+70
275.7k 992
Comments 65
Top of the day