Установка и настройка почтового сервера.
Предисловие
Склеротичка сия призвана облегчить воспроизведение уже полученного мною результата :) Почтовая система будет использовать следующие программные компоненты:
- Gentoo Linux
- app-antivirus/clamav
- app-antivirus/drweb
- dev-db/mysql
- mail-filter/amavisd-new
- mail-filter/dkim-milter
- mail-filter/dk-milter
- mail-mta/postfix
- net-mail/dovecot
- www-apps/postfixadmin
Создаваемая система будет поддерживать произвольное количество виртуальных почтовых доменов, с произвольным количеством email адресов в каждом домене.
В заключительной части будут рассмотрены вопросы миграции пользователей с существующей системы.
Общая архитектура ситемы
Ядро почтовой системы основано на MTA postfix и POP3/IMAP-сервере dovecot. Кроме того, postfix использует dovecot как LDA, а также для авторизации пользователей. Для хранения информации об обслуживаемых доменах, учётных записей пользователей и т.п. используется СУБД MySQL.
Обвязка ядра состоит из:
- web-интерфейса управления пользователями и доменами – postfixadmin
- системы фильтрации почты на этапе после принятия письма на основе dkim-milter, dk-milter, amavisd-new, clamav, drweb и spamassassin
- системы фильтрации почты на этапе до принятия письма на основе пакета grey-postfix
Спам-фильтрация будет выполняться в два этапа: на этапе приема письма, на основе серых списков и RBL, а также на этапе проверки содержимого письма программой spamassassin (письмо будет маркироваться как спам/неспам, но будет доставляться адресату в любом случае).
Фильтрация вирусов выполняется каскадом из двух антивирусов: drweb и clamav. С учётом того, что на стороне клиентов, скорее всего, стоит какой-то иной антивирус, это обеспечивает гарантированную фильтрацию заражённого контента.
Как SMTP-, так и POP3/IMAP-сервера будут поддерживать работу в режимах шифрованного соединения (STARTTLS или over SSL). А SMTP-сервер будет поддерживать авторизацию пользователей и релеинг писем авторизованных пользователей.
Установка софта
Подключение оверлеев
В файле /etc/layman/layman.cfg к списку оверлеев добавляем информацию об оверлее sabitov-overlay:
- /etc/layman/layman.cfg
overlays : http://www.gentoo.org/proj/en/overlays/repositories.xml http://sabitov.pp.ru/overlay/sabitov-overlay.xml
Собственно, подключаем оверлеи:
layman -a crg layman -a sabitov-overlay
USE-флаги
- /etc/portage/package.use
app-antivirus/drweb -X daemon logrotate mail-filter/amavisd-new spamassassin mail-mta/postfix dovecot-sasl -mbox mysql -pam sasl ssl vda net-mail/dovecot -berkdb bzip2 caps maildir managesieve -mbox mysql -pam sieve ssl -vpopmail zlib www-apps/postfixadmin extras mysql vhosts
Значимыми USE-флагами являются:
- dovecot-sasl -mbox mysql -pam sasl ssl vda для postfix
- maildir managesieve -mbox mysql -pam sieve ssl для dovecot
Разрешаем ставить «нестабильный» пакет для управления нашей почтовой системой:
- /etc/portage/package.keywords/mail_server
www-apps/postfixadmin
Установка
Ниже указаны только те пакеты, которые нам нужны явно. Их возможные зависимости опущены. Подразумевается, что MySQL (dev-db/mysql), Apache (www-servers/apache), PHP (dev-lang/php) уже установлены, настроены и работают. Установка пакета drweb обсуждается отдельно!
#У нас есть удачный повод обновить систему! :) emerge --sync -v layman -S eix-update emerge --nospinner -uDNvt --with-bdeps y world revdep-rebuild -i #проверяем что у нас будет устанавливаться. emerge -pvt dev-perl/Mail-SPF mail-filter/amavisd-new mail-mta/postfix net-mail/dovecot www-apps/postfixadmin mail-filter/dkim-milter #если всё ОК, запускаем установку и пьём... кофе. Нам нужен работающий мозГ emerge -avt dev-perl/Mail-SPF mail-filter/amavisd-new mail-mta/postfix net-mail/dovecot www-apps/postfixadmin mail-filter/dkim-milter
Настройка
MySQL
Для работы почтовой системы создаём две базы в MySQL: для хранения информации о пользователях и доменах, а также для работы фильтра по серым спискам.
# mysql mysql <<EOT CREATE DATABASE mail DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; GRANT ALL PRIVILEGES ON mail.* TO postfixadmin@localhost IDENTIFIED BY 'postfixadmin-passwd'; GRANT SELECT ON mail.* TO dovecot@localhost IDENTIFIED BY 'dovecot-passwd'; GRANT SELECT ON mail.* TO postfix@localhost IDENTIFIED BY 'postfix-passwd'; FLUSH PRIVILEGES; EOT
Создаём базу данных mail и трёх пользователей: postfixadmin — для административного интерфейса с полным доступом к базе, dovecot и postfix — для работы с базой одноименных почтовых демонов. Принципиально возможно объединить последних пользователей, но из интуитивных соображений было принято решение создать отдельных пользователей для каждого демона.
Таблицы в данной базе создаются автоматически при первом обращении к административному интерфейсу.
greylisting
Создаем базу greylisting и пользователя для работы с базой, после чего создаем набор таблиц, обеспечивающих работу спам-фильтра.
# mysql mysql <<EOT CREATE DATABASE graylisting DEFAULT CHARACTER SET latin1; GRANT ALL PRIVILEGES ON graylisting.* TO antispam@localhost IDENTIFIED BY 'greylisting-passwd'; FLUSH PRIVILEGES; USE graylisting; DROP TABLE IF EXISTS Tokens; CREATE TABLE Tokens ( client_address VARCHAR(15) NOT NULL DEFAULT '', sender VARCHAR(241) NOT NULL DEFAULT '', recipient VARCHAR(241) NOT NULL DEFAULT '', val INT(11) DEFAULT NULL, client_name VARCHAR(250) DEFAULT NULL, PRIMARY KEY (client_address,sender,recipient) ); DROP TABLE IF EXISTS domain_black_list; CREATE TABLE domain_black_list ( DOMAIN VARCHAR(241) NOT NULL DEFAULT '', insert_time INT(11) DEFAULT NULL, PRIMARY KEY (DOMAIN) ); DROP TABLE IF EXISTS domain_white_list; CREATE TABLE domain_white_list ( DOMAIN VARCHAR(241) NOT NULL DEFAULT '', PRIMARY KEY (DOMAIN) ); DROP TABLE IF EXISTS force_delivering_recipients; CREATE TABLE force_delivering_recipients ( recipient VARCHAR(241) NOT NULL DEFAULT '', PRIMARY KEY (recipient) ); DROP TABLE IF EXISTS ip_black_list; CREATE TABLE ip_black_list ( IP VARCHAR(15) NOT NULL DEFAULT '', insert_time INT(11) DEFAULT NULL, PRIMARY KEY (IP) ); DROP TABLE IF EXISTS ip_white_list; CREATE TABLE ip_white_list ( IP VARCHAR(15) NOT NULL DEFAULT '', PRIMARY KEY (IP) ); DROP TABLE IF EXISTS sender_black_list; CREATE TABLE sender_black_list ( sender VARCHAR(241) NOT NULL DEFAULT '', PRIMARY KEY (sender) ); DROP TABLE IF EXISTS sender_white_list; CREATE TABLE sender_white_list ( IP VARCHAR(15) NOT NULL DEFAULT '', sender VARCHAR(241) NOT NULL DEFAULT '', PRIMARY KEY (IP,sender) ); DROP TABLE IF EXISTS user_contact_list; CREATE TABLE user_contact_list ( sender VARCHAR(241) NOT NULL DEFAULT '', recipient VARCHAR(241) NOT NULL DEFAULT '', IP VARCHAR(15) NOT NULL DEFAULT '', PRIMARY KEY (sender,recipient,IP) ); DROP TABLE IF EXISTS wellcome_back_tokens; CREATE TABLE wellcome_back_tokens ( sender VARCHAR(241) NOT NULL DEFAULT '', recipient VARCHAR(241) NOT NULL DEFAULT '', val INT(11) DEFAULT NULL, PRIMARY KEY (sender,recipient) ); EOT
Clamav
Ставится в дефолтовой конфигурации.
- /etc/clamd.conf
AllowSupplementaryGroups yes
Spamassassin
Ставиться в дефолтовой конфигурации.
- /etc/mail/spamassassin/local.cf
trusted_networks 172.16. 172.17. 111.222.55. 111.222.33.
Указываем сети, которые не будут проверяться на спам. Для целей отладки разумным будет указать какой-нибудь несуществующий IP-адрес, например, 1.1.1.1, а потом прописать разумные значения.
Обновляем правила фильтрации:
wget "http://spamassassin.apache.org/updates/GPG.KEY" wget "http://saupdates.openprotect.com/pub.gpg" sa-update --import GPG.KEY sa-update --import pub.gpg sa-update -D sa-update --allowplugins --gpgkey D1C035168C1EBC08464946DA258CDB3ABDE9DC10 --channel saupdates.openprotect.com sa-compile
DrWeb
На момент установки ebuild искал дистрибутив по неправильному URL. Скачиваем дистрибутив, устанавливаем, корректируем права доступа и выкладываем ключ.
cd /usr/portage/distfiles/ wget -t0 -c ftp://ftp.drweb.com/pub/drweb/unix/archive/Linux/Generic/drweb-4.44.3-unix-glibc27.tar.bz2 emerge -pvt app-antivirus/drweb emerge -avt app-antivirus/drweb chown -R drweb:drweb /var/drweb/ chmod +x /opt/drweb/{drweb.static,drwebd.static,drwebdc,read_signed,read_signed.static} mv drweb32.key /opt/drweb/drweb32.key
Оптимизируем для работы с почтой:
- /etc/drweb/drweb32.ini
StopOnFirstInfected = Yes FilesTypesWarnings = No CheckArchives = Yes CheckEMailFiles = Yes
Amavisd-new
Создаём категории в карантине и раздаём на них права:
mkdir /var/amavis/quarantine/{virus,spam,banned,badh,clean} chown -R amavis:amavis /var/amavis/quarantine/* chmod -R gu=rwX /var/amavis/quarantine/* chmod -R o-rwx /var/amavis/quarantine/*
Добавляем пользователей clamav и drweb в группу amavis, чтобы amavisd мог отдавать письма на проверку
gpasswd -a clamav amavis gpasswd -a drweb amavis
Необходимо проверить настройки и привести их к таким значениям:
- /etc/amavisd.conf
$myhostname = 'yam.sabitov.su'; $inet_socket_port = 10024; $inet_socket_bind = '127.0.0.1'; @inet_acl = qw(127.0.0.1); $final_virus_destiny = D_DISCARD; # (defaults to D_DISCARD) $final_banned_destiny = D_BOUNCE; # (defaults to D_BOUNCE) $final_spam_destiny = D_PASS; # (defaults to D_BOUNCE) $final_bad_header_destiny = D_PASS; # (defaults to D_PASS) $warnvirusrecip = 1; # (defaults to false (undef)) $warnbannedrecip = 1; # (defaults to false (undef)) $warn_offsite = 1; # (defaults to false (undef), i.e. only notify locals) $virus_admin = undef; $spam_admin = undef; $mailfrom_notify_admin = "virusalert\@$mydomain"; $mailfrom_notify_recip = "virusalert\@$mydomain"; $mailfrom_notify_spamadmin = "spam.police\@$mydomain"; $virus_quarantine_method = 'local:virus/%m'; $spam_quarantine_method = 'local:spam/%m.gz'; $banned_files_quarantine_method = 'local:banned/%m'; $bad_header_quarantine_method = 'local:badh/%m'; $virus_quarantine_to = 'virus-quarantine'; # traditional local quarantine $banned_quarantine_to = 'banned-quarantine'; # local quarantine $bad_header_quarantine_to= 'bad-header-quarantine'; # local quarantine $spam_quarantine_to = 'spam-quarantine'; # local quarantine $X_HEADER_TAG = 'X-Virus-Scanned'; # (default: 'X-Virus-Scanned') $X_HEADER_LINE = "by $myproduct_name using ClamAV at $mydomain"; $remove_existing_x_scanned_headers = 0; $remove_existing_spam_headers = 1;
Необходимо закомментировать все варианты антивирусов в массиве @av_scanners, после чего снять комментарии с элементов ClamAV-clamd и DrWebD. Кроме того, в элементе ClamAV-clamd надо изменить путь к сокету на /var/run/clamav/clamd.sock, а в элементе DrWebD путь к сокету изменить на /var/drweb/run/.daemon
Чтобы локализовать сервисные уведомления о вирусах и т.п. (DSN) Необходимо:
mkdir /etc/amavis/ru_RU
В этой директории создаём файлы (они необходимы все, даже если нет желания локализовывать какое-то конкретное сообщение):
charset template-dsn.txt template-spam-admin.txt template-spam-sender.txt template-virus-admin.txt template-virus-recipient.txt template-virus-sender.txt
В charset прописываем единственную строку UTF-8
.
Содержимое остальных файлов либо берём из дебиановского пакета, либо творчески выпиливаем из /usr/sbin/amavisd
. Например, ниже этой строки «This is a template for VIRUS/BANNED SENDER NOTIFICATIONS» идёт шаблон сообщения о вирусе, отправляемого отправителю письма. Получившиеся шаблоны редактируем и переводим на велико-могучий, проверяем, в какой кодировке мы их написали (должно быть UTF-8).
Правим основной конфиг:
- /etc/amavisd.conf
$bdy_encoding = 'UTF-8'; # (default: 'iso-8859-1') read_l10n_templates('/etc/amavis/ru_RU'); $warnvirusrecip = 1;<--># (defaults to false (undef)) $warnbannedrecip = 1;<-># (defaults to false (undef)) $warn_offsite = 1;<----># (defaults to false (undef), i.e. only notify locals)
Dovecot
Создаём самоподписанный сертификат для dovecot и выкладываем куда положено:
mv /home/sabitov/dovecot_at_yam.sabitov.su.{key,pem} /etc/ssl/dovecot/ chown dovecot:mail /etc/ssl/dovecot/dovecot_at_yam.sabitov.su*
Описываем параметры подключения к базе:
- /etc/dovecot/dovecot-sql.conf
driver = mysql connect = host=/var/run/mysqld/mysqld.sock user=dovecot password=dovecot-passwd dbname=mail default_pass_scheme = MD5 user_query = SELECT CONCAT('/var/mail/', maildir) AS home, CONCAT('*:bytes=', quota) AS quota_rule FROM mailbox WHERE username = '%u' AND active = 1 password_query = SELECT CONCAT('/var/mail/', maildir) AS userdb_home, username as user, password, CONCAT('*:bytes=', quota) AS userdb_quota_rule FROM mailbox WHERE username = '%u' AND active = 1
Будем поддерживать как POP3, так и IMAP протоколы, а также их SSL варианты. Сверх этого, будем поддерживать SIEVE-скрипты, для чего активируем протокол managesieve, и указываем плагин sieve в секции lda.
- /etc/dovecot/dovecot.conf
protocols = imap imaps pop3 pop3s managesieve listen = * disable_plaintext_auth = no ssl = yes ssl_cert_file = /etc/ssl/dovecot/dovecot_at_yam.sabitov.su.pem ssl_key_file = /etc/ssl/dovecot/dovecot_at_yam.sabitov.su.key ssl_key_password = dovecot_cert_pwd login_greeting = OOPS server ready mail_location = maildir:/var/mail/%d/%n/Maildir/:INDEX=/var/mail/%d/%n/indexes mail_uid = 8 mail_gid = 12 first_valid_uid = 8 last_valid_uid = 8 first_valid_gid = 12 last_valid_gid = 12 protocol imap { mail_plugins = quota imap_quota } protocol pop3 { mail_plugins = quota } protocol managesieve { } protocol lda { postmaster_address = postmaster@yam.sabitov.su mail_plugins = quota sieve } auth default { mechanisms = plain login passdb sql { args = /etc/dovecot/dovecot-sql.conf } userdb sql { args = /etc/dovecot/dovecot-sql.conf } userdb prefetch { } user = nobody socket listen { master { path = /var/run/dovecot/auth-master mode = 0600 user = mail group = mail } client { path = /var/spool/postfix/private/auth mode = 0660 user = postfix group = postfix } } }
Postfixadmin
Устанавливаем postfixadmin под наш виртуальный сервер:
webapp-config -I -h localhost -d postfixadmin postfixadmin 2.3
Закрываем доступ всем, кроме тех кому можно:
- /var/www/localhost/htdocs/postfixadmin/.htaccess
Order Deny,Allow Deny from all Allow from 111.222.33. 172.16. 172.17. Satisfy all
После чего настраиваем. Файл config.inc.php не трогаем! Он будет постоянно переписываться при обновлениях, так что все локальные установки вносим в файл config.local.php
- /var/www/localhost/htdocs/postfixadmin/config.local.php
#$CONF['configured'] = false; $CONF['postfix_admin_url'] = 'https://yam.sabitov.su/postfixadmin'; $CONF['database_type'] = 'mysql'; $CONF['database_host'] = 'localhost'; $CONF['database_user'] = 'postfixadmin'; $CONF['database_password'] = 'postfixadmin-passwd'; $CONF['database_name'] = 'mail'; $CONF['database_prefix'] = ''; $CONF['admin_email'] = 'postmaster@yam.sabitov.su'; $CONF['encrypt'] = 'md5crypt'; $CONF['min_password_length'] = 6; $CONF['page_size'] = '100'; $CONF['domain_path'] = 'YES'; $CONF['domain_in_mailbox'] = 'NO'; $CONF['aliases'] = '0'; $CONF['mailboxes'] = '0'; $CONF['maxquota'] = '0'; $CONF['quota_multiplier'] = '1048576'; $CONF['user_footer_link'] = "http://yam.sabitov.su/postfixadmin/users";
Завершаем установку посетив ссылку http://yam.sabitov.su/postfixadmin/setup.php. Будет запрошено создание административного эккаунта и созданы таблицы в базе mail. По завершению работы скритпа setup.php, его необходимо удалить, и отредактировать config.inc.php:
rm /var/www/localhost/htdocs/postfixadmin/setup.php
- /var/www/localhost/htdocs/postfixadmin/config.inc.php
$CONF['configured'] = true;
DKIM (DomainKeys Identified Mail)
Пруф-линки на описание технологии:
- вначале по-русски, но очень коротко о том, что это такое вообще: http://ru.wikipedia.org/wiki/DomainKeys_Identified_Mail,
- а потом кладезь информации: http://www.dkim.org
На момент написания гента имеет 3 альтернативных пакета для работы с DKIM: mail-filter/zdkimfilter, mail-filter/dkim-milter, mail-filter/opendkim. Выбираем второй вариант. Почему? Ну, какой-то ж надо выбрать :) Да, с DKIM умеет работать и амавис, но как подписывать разными ключами письма из разных доменов я не разобрался, так что если есть только один домен, то имеет смысл посмотреть как это всё делается амависом.
Правим /etc/mail/dkim-filter/dkim-filter.conf. Ниже показаны только те значения, которые менялись в конфиге, некоторые из них содержат дефолтовые значения для того, чтобы подчеркнуть, что нас интересует именно это значение, пусть даже дефолтовое.
- /etc/mail/dkim-filter/dkim-filter.conf
ADSPDiscard yes ADSPNoSuchDomain No AllowSHA1Only no AlwaysAddARHeader yes AuthservID yam.sabitov.su AuthservIDWithJobId yes AutoRestart yes AutoRestartCount 0 AutoRestartRate 1/1s BaseDirectory /var/run/dkim-filter BodyLengths yes Canonicalization simple/simple ClockDrift 4200 Domain /etc/mail/dkim-filter/local-domains EnableCoredumps no FixCRLF no KeepTemporaryFiles no #KeyFile /etc/mail/dkim-filter/my-selector-name.private KeyList /etc/mail/dkim-filter/keylist LogWhy no Mode sv OmitHeaders X-DomainKeys,DomainKey-Signature On-Default accept On-BadSignature reject On-DNSError tempfail On-InternalError tempfail On-NoSignature accept On-Security tempfail Quarantine no QueryCache no RemoveOldSignatures yes ReportAddress postmaster@yam.sabitov.su Selector default SendADSPReports no SendReports yes SubDomains no Syslog yes SyslogFacility mail SyslogSuccess yes X-Header yes
Необходимо отметить несколько параметров:
- ClockDrift – максимально допустимое расхождение в показаниях часов между нашим сервером и тем удалённым. 4200 выбрано как 10 мин расхождения + 1 час при переходах с летнего на зимнее время и обратно (да, у нас этот дурдом отменили наконец, но есть же еще страны кроме Москвы и России)
- Domain – содержит либо список локальных доменов, либо имя файла с таким списком. Формат файла – один домен на одной строке. Очевидно, что второй вариант интересней. Письма идущие из локальных доменов будут подписываться, из остальных доменов – проверяться.
- KeyFile и KeyList – Первый параметр указывает имя файла с первичным ключём, и используется если мы для всех наших локальных доменов будем использовать один единственный ключ. Исходя из интуитивных соображений, стоит для каждого локального домена использовать свой ключ. Для этого указываем имя файла с описаниями этих ключей в параметре KeyList. Формат файла описан в мане. :)
- Selector – как сказано в мане: See the DKIM specification for details. :) Для нас важно, что имена файлов с ключами будут default.{private,txt}.
Правим список ключей:
- /etc/mail/dkim-filter/keylist
*@yam.catalysis.ru:yam.catalysis.ru:/etc/mail/dkim-filter/keys/yam.catalysis.ru/default
Создаём директории для ключей, и генерим сами ключи:
mkdir -p /etc/mail/dkim-filter/keys/yam.catalysis.ru cd /etc/mail/dkim-filter/keys/yam.catalysis.ru dkim-genkey -s default -d yam.catalysis.ru
Добавляем пользователя postfix в группу milter
Правим файл с DNS-зоной:
- /chroot/dns/var/bind/pri/yam.catalysis.ru
@ IN TXT "v=spf1 +mx +a:yam.catalysis.ru ~all" _domainkey IN TXT "o=-" _adsp._domainkey IN TXT "dkim=discardable; t=s" default._domainkey IN TXT "v=DKIM1; g=*; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCl/u9Yy42TRSDj9WtByAMGL6j9aKI8M4eu2dWQuTA6pDR4pDFSC7dSXzyC4aSMj21EI4Ec3Utr1OZYywF94+8x54OA/pllOf66SLnIhZ17LFGP046m6eS/UUsKk3SU4R4l/o9cXt41VAMb1Kqayh9XtgkTyIkCEvxkA0zM4T+sWwIDAQAB" ; ----- DKIM default for yam.catalysis.ru
Первая строка, разумеется, к DKIM'у отношения не имеет, но уж коли всё равно полезли DNS править, почему бы ещё и SPF не прописать. Открытый ключ (запись default._domainkey) берём из /etc/mail/dkim-filter/keys/yam.catalysis.ru/default.txt. Запись _adsp._domainkey либо создаём «ручками» после прочтения RFC5617, либо пользуемся этой формочкой. Запись _domainkey указывает, что исходящие письма из нашего домена обязаны быть подписаны.
Domain Keys
DomainKeys не тоже самое, что и DKIM. Если мы настроили работу DKIM, нам с неизбежностью прийдется настроить и DomainKeys. Дело в том, что есть странные почтовые сервера (например: mail1.slovo-pub.ru, mail.cipu.ru, mail2.comicsoid.ru, ms1.textbook.ru, drofaweb.drofa.ru), которые настроены на работу с DomainKeys, и не знают ничего про DKIM. Если в наших письмах будет только DKIM-сигнатура, эти стренджеры будут проверять её как DomainKeys-сигнатуру. В результате такой проверки мы получим в логах такое сообщение:
Aug 22 08:58:48 mail postfix/smtp[20245]: 5EE8730729: to=<xxx@drofa.ru>, relay=drofaweb.drofa.ru[62.231.7.194]:25, delay=6.5, delays=0.04/0.01/5.5/0.97, dsn=5.0.0, status=bounced (host drofaweb.drofa.ru[62.231.7.194] said: 550 Message does not pass DomainKeys requirements for domain sabitov.su (in reply to end of DATA command))
Чтобы решить сию проблему на корню включаем проверку и подписывание DomainKeys-сигнатур. Вначале ставим софтину:
echo "mail-filter/dk-milter" >> /etc/portage/package.keywords/mail emerge -vt mail-filter/dk-milter emerge --config mail-filter/dk-milter
В диалоге при конфигурации говорим, что селектор у нас будет dk, размер ключа – 1024. Из того что вывалится на экран мышкой копируем TXT-запись в файл зоны. Что-то типа такого:
dk._domainkey IN TXT "g=\; k=rsa\; t=y\; o=~\; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCnW0VmMAiTS7iTosJD6bI6XoYKjYTR12yUuFIXG5l91FfzpkXFTJPq1qnlomxeXfJ6sCgF8RkiDDHdeYRIROv/dOwGZ6BgWFOszXM/VxMr80um7eTz/KPMa2D0SRl49X9ZNmudoNWrcMxXfi87wdQ2ecjsbYmDSFehBfB9m+ecFwIDAQAB"
Правим /etc/conf.d/dk-filter:
- /etc/conf.d/dk-filter
ADDITIONAL_OPTS="-l -b sv -d sabitov.su -H -s /etc/mail/dk-filter/dk.private -S dk \ -C badsignature=reject,dnserror=tempfail,internal=tempfail,nosignature=accept,signaturemissing=reject"
OpenDKIM
Из соображений «на всякий случай» предыдущие 2 раздела про dkim-filter и dk-filter оставляю, но в настоящий момент для генты актуальным остаётся mail-filter/opendkim, который заменяет собой оба предыдущих пакета.
Генерация ключей выполняется командой:
opendkim-genkey -D /etc/opendkim/keys/sabitov.su/ -d sabitov.su -s default
Если ключи уже есть (выполняем миграцию с предыдущих пакетов), то ничего делать по-новой не надо.
Настраиваем opendkim, как нам нравится. Указываем DomainKeysCompat
. Всё остальное аналогично тому, что было описано для dkim-filter.
- /etc/opendkim/opendkim.conf
###################################################################### # ## Author Domain Signing Practises # ###################################################################### ADSPAction reject ADSPNoSuchDomain no DisableADSP no ###################################################################### # ## Настройки проверки и подписания почты # ###################################################################### Mode sv AllowSHA1Only no AlwaysAddARHeader yes Canonicalization relaxed/simple ExternalIgnoreList refile:/etc/opendkim/client-hosts InternalHosts refile:/etc/opendkim/client-hosts SigningTable refile:/etc/opendkim/signing-table KeyTable refile:/etc/opendkim/key-table Selector default X-Header yes ### Списки, от кого не проверяем письма # по полю from #ExemptDomains # по IP адресу клиента #PeerList On-Default accept On-BadSignature reject On-DNSError tempfail On-InternalError tempfail On-NoSignature accept On-Security tempfail DomainKeysCompat yes OmitHeaders X-DomainKeys,DomainKey-Signature AuthservID mail.sabitov.su AuthservIDWithJobId yes RemoveOldSignatures yes SubDomains no ###################################################################### # ## Настройки производительности и т.п. # ###################################################################### AutoRestart yes AutoRestartCount 0 AutoRestartRate 1/1s ClockDrift 3600 BaseDirectory /var/run/opendkim/ DNSConnect yes DNSTimeout 10 QueryCache yes Socket inet:8891@localhost ReportAddress postmaster@example.com SendReports yes PidFile /var/run/opendkim/opendkim.pid Statistics /var/lib/opendkim/stats.dat UMask 002 UserID milter ###################################################################### # ## Настройки логирования # ###################################################################### Diagnostics yes DiagnosticDirectory /var/run/opendkim/ Syslog yes SyslogFacility mail SyslogSuccess yes LogWhy yes Quarantine no
- /etc/opendkim/client-hosts
127.0.0.1 !172.17.40.0/24 172.16.0.0/15
- /etc/opendkim/key-table
default._domainkey.sabitov.su sabitov.su:default:/etc/opendkim/keys/sabitov.su/default
- /etc/opendkim/signing-table
*@sabitov.su default._domainkey.sabitov.su
Postfix
Greylisting
Скрипты фильтра по серым спискам укладываем в /usr/local/greylisting, конфигурационный файл — в /etc/postfix.
chown -R root:root /usr/local/greylisting /etc/postfix/greyListing.conf chmod 644 /usr/local/greylisting/* /etc/postfix/greyListing.conf chmod 755 /usr/local/greylisting/*pl
Настраиваем параметры коннекта к базе и список поддерживаемых доменов:
- /etc/postfix/greyListing.conf
$dbName = "DBI:mysql:graylisting"; $dbUserName = "antispam"; $dbPassword = "greylisting-passwd"; @local_domains = ( 'yam.sabitov.su' );
Проверяем, что все работает:
cat /usr/local/greyListing/req-etalon | /usr/bin/perl /usr/local/greyListing/greylist.pl action=defer_if_permit Service is unavailable #!!!!!!!!Здесь должна быть пустая строка!!!!!!!!
Через $greylist_delay секунд повторяем попытку:
cat /usr/local/greyListing/req-etalon | /usr/bin/perl /usr/local/greyListing/greylist.pl action=dunno #!!!!!!!!Здесь должна быть пустая строка!!!!!!!!
Сертификаты
Создаём самоподписанный сертификат и выкладываем куда положено:
mv /home/sabitov/postfix_at_yam.sabitov.su.{pem,key} /etc/ssl/postfix/ chown postfix:mail /etc/ssl/postfix/postfix_at_yam.sabitov.su.{pem,key}
main.cf
- /etc/postfix/main.cf
myhostname = yam.sabitov.su myorigin = $myhostname inet_interfaces = all mydestination = #обязательно пустое значение!!! mynetworks = 127.0.0.0/8, 172.16.0.0/15, 111.222.55.0/24, 111.222.33.0/24 relayhost = elm.catalysis.ru alias_maps = hash:/etc/aliases, hash:/var/lib/mailman/data/aliases alias_database = hash:/etc/aliases ######################################################################## # ## Local settings appended to default config # ######################################################################## dovecot_destination_recipient_limit = 1 virtual_transport = dovecot #auth smtpd_sasl_auth_enable = yes broken_sasl_auth_clients = yes smtpd_sasl_type = dovecot smtpd_sasl_path = private/auth #tls smtp_use_tls = yes smtp_tls_note_starttls_offer = yes smtpd_tls_auth_only = yes smtpd_tls_security_level = may smtpd_tls_cert_file = /etc/ssl/postfix/postfix_at_yam.sabitov.su.pem smtpd_tls_key_file = /etc/ssl/postfix/postfix_at_yam.sabitov.su.key smtpd_tls_loglevel = 1 smtpd_tls_session_cache_timeout = 3600s tls_random_source = dev:/dev/urandom #MySQL integration virtual_alias_maps = mysql:/etc/postfix/mysql_virtual_alias_maps.cf virtual_mailbox_domains = mysql:/etc/postfix/mysql_virtual_domain_maps.cf virtual_mailbox_maps = mysql:/etc/postfix/mysql_virtual_mailbox_maps.cf #Other options smtpd_helo_required = yes smtpd_helo_restrictions = permit_mynetworks, reject_invalid_hostname, check_helo_access hash:/etc/postfix/helo_access smtpd_sender_restrictions = reject_non_fqdn_sender, reject_unknown_sender_domain smtpd_client_restrictions = hash:/etc/postfix/access, reject_rbl_client zen.spamhaus.org, regexp:/etc/postfix/auto_spam.cf smtpd_data_restrictions = reject_unauth_pipelining, reject_multi_recipient_bounce smtpd_recipient_restrictions = check_policy_service unix:private/greypolicy, permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination greypolicy_time_limit = 3600 #за 10 мин. 20 писем с одного IP anvil_rate_time_unit = 600s anvil_status_update_time = 1h smtpd_client_message_rate_limit = 20 data_directory = /var/lib/postfix strict_rfc821_envelopes = yes disable_vrfy_command = yes message_size_limit = 33000000 mailbox_size_limit = 512000000 html_directory = no smtpd_milters = unix:/var/run/dk-filter/dk-filter.sock, unix:/var/run/dkim-filter/dkim-filter.sock non_smtpd_milters = unix:/var/run/dk-filter/dk-filter.sock, unix:/var/run/dkim-filter/dkim-filter.sock
master.cf
Правим имеющееся и дополняем недостающее:
- /etc/postfix/master.cf
smtp inet n - n - - smtpd -o content_filter=amavis:[127.0.0.1]:10024 -o receive_override_options=no_address_mappings smtps inet n - n - - smtpd -o smtpd_tls_wrappermode=yes -o smtpd_sasl_auth_enable=yes -o smtpd_client_restrictions=permit_sasl_authenticated,reject -o content_filter=amavis:[127.0.0.1]:10024 -o receive_override_options=no_address_mappings ######################################################################## # ## Local settings appended to default config # ######################################################################## # Use dovecot as LDA dovecot unix - n n - - pipe flags=DRhu user=mail:mail argv=/usr/libexec/dovecot/deliver -f ${sender} -d ${recipient} # Use lmtp to deliver messages to amavis amavis unix - - n - 4 lmtp -o disable_dns_lookup=yes -o lmtp_send_xforward_command=yes -o lmtp_data_done_timeout=1200 # Injecting mail back into Postfix after content filter amavis. localhost:10025 inet n - n - 2 smtpd -o content_filter= -o myhostname=yam.sabitov.su -o local_recipient_maps= -o relay_recipient_maps= -o smtpd_restriction_classes= -o smtpd_client_restrictions= -o smtpd_helo_restrictions= -o smtpd_sender_restrictions= -o smtpd_recipient_restrictions=permit_mynetworks,reject -o mynetworks=127.0.0.0/8 -o strict_rfc821_envelopes=yes -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_unknown_recipient_checks,no_header_body_checks -o smtpd_authorized_xforward_hosts=127.0.0.0/8 # Greylisting filter greypolicy unix - n n - - spawn user=nobody argv=/usr/bin/perl /usr/local/greyListing/greylist.pl
Вспомогательные конфигурационные файлы
- /etc/postfix/access
172.16 OK 172.17 OK 111.222.33 OK 111.222.55 OK
- /etc/postfix/auto_spam.cf
#regexp SMTP response code /^dsl-.*\.solcon\.nl/i 250 OK /^dsl.*\..*\..*/i 553 AUTO_DSL spam #/[ax]dsl.*\..*\..*/i 553 AUTO_XDSL spam /xdsl.*\..*\..*/i 553 AUTO_XDSL spam /client.*\..*\..*/i 553 AUTO_CLIENT spam /cable.*\..*\..*/i 553 AUTO_CABLE spam /pool.*\..*\..*/i 553 AUTO_POOL spam /dial.*\..*\..*/i 553 AUTO_DIAL spam /ppp.*\..*\..*/i 553 AUTO_PPP spam /dslam.*\..*\..*/i 553 AUTO_DSLAM spam #/node.*\..*\..*/i 553 AUTO_NODE spam #/dynamic.*\..*\..*\..*/i 553 AUTO_DINAMIC spam /.*\.dsl\.brasiltelecom\.net\.br/i 553 AUTO_DSL spam /.*\..*\.res\.rr\.com/i 553 AUTO_SPAM spam /.*\.ed\.shawcable\.net/i 553 AUTO_SPAM spam /.*\.dhcp\.oxfr\.ma\.charter\.com/i 553 AUTO_DHCP spam /.*dhcp\..*\.atlanticbb\.net/i 553 AUTO_SPAM spam
- /etc/postfix/helo_access
yam.sabitov.pp.ru REJECT Get lost yam.sabitov.su REJECT Get lost
- /etc/postfix/mysql_virtual_alias_maps.cf
user = postfix password = postfix-passwd hosts = localhost dbname = mail query = SELECT goto FROM alias WHERE address='%s' AND active = '1'
- /etc/postfix/mysql_virtual_domain_maps.cf
user = postfix password = postfix-passwd hosts = localhost dbname = mail query = SELECT domain FROM domain WHERE domain='%s' AND backupmx = '0' AND active = '1'
- /etc/postfix/mysql_virtual_mailbox_maps.cf
user = postfix password = postfix-passwd hosts = localhost dbname = mail query = SELECT CONCAT(maildir, 'Maildir/') AS maildir FROM mailbox WHERE username='%s' AND active = '1'
Пересобираем хеши:
newaliases postmap /etc/postfix/access postmap /etc/postfix/auto_spam.cf postmap /etc/postfix/helo_access
Запуск системы и тестирование
/etc/init.d/dovecot restart /etc/init.d/dk-filter restart /etc/init.d/dkim-filter restart /etc/init.d/clamd restart /etc/init.d/drwebd restart /etc/init.d/spamd restart /etc/init.d/amavisd restart /etc/init.d/postfix restart netstat -nltp netstat -nlxp rc-update add dovecot default rc-update add dk-filter default rc-update add dkim-filter default rc-update add clamd default rc-update add drwebd default rc-update add spamd default rc-update add amavisd default rc-update add postfix default /opt/drweb/update.pl
TCP-сокеты, которые должны прослушивать демоны:
- 25, 465, 10025 — master (postfix)
- 110, 143, 993, 995, 2000 — dovecot
- 10024 — amavisd
UNIX-сокеты, которые должны прослушивать демоны:
- /var/drweb/run/.daemon — drwebd
- /var/run/dovecot/login/default, /var/run/dovecot/auth-master, /var/spool/postfix/private/auth — dovecot
- /var/run/clamav/clamd.sock — clamd
- /var/amavis/amavisd.sock — amavisd
- private/greypolicy, private/amavis, private/dovecot — master
- /var/run/dk-filter/dk-filter.sock — dk-filter
- /var/run/dkim-filter/dkim-filter.sock — dkim-filter
Для дальнейшего тестирования системы необходимо через административный интерфейс postfixadmin завести несколько пользователей и настроить почтовый клиент (thunderbird рулит!) на чтение их почты. Необходимо учитывать, что имя пользователя, в нашем случае, будет совпадать с его email'ом. Для проверки работы sieve-скриптов, рекомендуется установить дополнение sieve (https://addons.mozilla.org/ru/thunderbird/addon/2548/), и с его помощью создать простейшие скрипты для проверки.
Миграция
Скрипт переноса системных пользователей (/etc/passwd, /etc/shadow) в базу виртуального домена. На входе принимает имена passwd-файла, shadow-файла и имя домена, которому будут принадлежать пользователи. На выходе имеем SQL-скрипт, с готовыми данными для загрузки в базу.
При переносе пользователей, рекомендуется сделать копии файлов /etc/passwd и /etc/shadow, после чего из копии passwd необходимо удалить пользователей, которых не следует переносить в новую почтовую систему. (Копию shadow можно при этом не редактировать.)
- mkvirtual
#!/usr/bin/perl -w use strict; my %passwd = (); my %shadow = (); sub read_passwd ($) { my $file_name = shift; open INPUT, $file_name || die; while ( my $line = <INPUT> ) { my @line = split ( ':', $line ); my $login = shift @line; $passwd { $login } = \@line; } close INPUT; } sub read_shadow ($) { my $file_name = shift; open INPUT, $file_name || die; while ( my $line = <INPUT> ) { my @line = split ( ':', $line ); my $login = shift @line; $shadow { $login } = \@line; } close INPUT; } sub print_sql ($) { my $domain = shift; foreach my $key ( sort ( keys %passwd ) ) { my $username = $key . '@' . $domain; my $password = defined $shadow{$key}->[0] ? $shadow{$key}->[0] : '!'; my $name = defined $passwd{$key}->[3] ? $passwd{$key}->[3] : $key; my $maildir = $domain . '/' . $key . '/'; my $quota = 0; my $local_part = $key; my $active = 1; print "INSERT INTO mailbox (username, password, name, maildir, quota, local_part, domain, created, modified, active) " . "VALUES ( '$username', '$password', '$name', '$maildir', $quota, '$local_part', '$domain', NOW(), NOW(), $active);\n"; print "INSERT INTO alias (address, goto, domain, created, modified, active) " . "VALUES ( '$username', '$username', '$domain', NOW(), NOW(), $active);\n\n"; } } my $passwd_file = shift @ARGV; my $shadow_file = shift @ARGV; my $domain_name = shift @ARGV; read_passwd ( $passwd_file ); read_shadow ( $shadow_file ); print_sql ( $domain_name );
— Andrew A. Sabitov 2010-11-23 18:07