Установка и настройка почтового сервера.

Предисловие

Склеротичка сия призвана облегчить воспроизведение уже полученного мною результата :) Почтовая система будет использовать следующие программные компоненты:

  • 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
/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 <<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 и пользователя для работы с базой, после чего создаем набор таблиц, обеспечивающих работу спам-фильтра.

# 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

Ставится в дефолтовой конфигурации.

/etc/clamd.conf
AllowSupplementaryGroups yes

Ставиться в дефолтовой конфигурации.

/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

На момент установки 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

Создаём категории в карантине и раздаём на них права:

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 и выкладываем куда положено:

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 под наш виртуальный сервер:

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;

Пруф-линки на описание технологии:

На момент написания гента имеет 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}.
В качестве TODO: при изменении списка доменов через postfixadmin, можно автоматом пересобирать /etc/mail/dkim-filter/local-domains. Копать в сторону хуков. С другой стороны, для каждого домена указывается свой ключ, который надо сгенерить, положить куда следует, добавить запись в /etc/mail/dkim-filter/keylist (это всё можно сделать автоматически тем же хуком) и (sic!) прописать в DNS – всё равно ручная работа…

Правим список ключей:

/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 указывает, что исходящие письма из нашего домена обязаны быть подписаны.

На заре цивилизации использовались записи _ssp._domainkey, потом их переименовали в _asp._domainkey, потом появились _adsp._domainkey.

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"

Из соображений «на всякий случай» предыдущие 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

Скрипты фильтра по серым спискам укладываем в /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}
/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

Правим имеющееся и дополняем недостающее:

/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

  • sys/установка_и_настройка_почтового_сервера.txt
  • Последнее изменение: 2012-12-17 10:10
  • Andrew A. Sabitov