воскресенье, 23 февраля 2014 г.

Установка и настройка Roundcube

Заключительная статья из серии статей о настройке почтовой системы. В прошлых заметках была рассмотрена настройка серверной части почтовой системы, настройка SSL/TLS и настройка почтового клиента Thunderbird/Icedove: Установка и настройка Postfixadmin, Установка и настройка Dovecot, Установка и настройка Postfix, OpenDKIM, ClamAV-Milter, Milter-Greylist и Настройка SSL/TLS в Postfix, Dovecot, Lighttpd, Дополнения Thunderbird/Icedove.

На этот раз мы рассмотрим настройку почтового веб-клиента Roundcube.

Для работы Roundcube понадобится веб-сервер с поддержкой PHP и одна из СУБД: MySQL, PostgreSQL (в настройках самого Roundcube была ещё замечена возможность работы с SQLite, однако в пакетах никаких признаков поддержки SQLite обнаружено не было).

1. Установка пакетов и создание базы данных

Установим необходимые пакеты, если они ещё не установлены:
# apt-get install mysql-server mysql-client lighttpd php5-cgi
Установим Roundcube и пакеты с дополнительными плагинами:
# apt-get install roundcube php-auth-sasl roundcube-plugins roundcube-plugins-extra
В процессе установки пакета roundcube-core будет предложено настроить базу данных для Roundcube:
Запрос автоматической настройки базы данных
Запрос пароля администратора СУБД
2. Настройка веб-сервера

Подготовим файл /etc/lighttpd/conf-available/50-roundcube.conf, используя для его составления информацию из файлов /etc/roundcube/lighttpd.conf и /usr/share/roundcube/.htaccess:
$HTTP["host"] == "mail.domain.tld" {

  server.document-root = "/var/lib/roundcube"

  alias.url += ( "program/js/tiny_mce" => "/usr/share/tinymce/www",
                 "favicon.ico" => "/usr/share/roundcube/skins/default/images/favicon.ico" )

  $HTTP["url"] =~ "^/config|/temp|/logs" {
    url.access-deny = ( "" )
  }
}
Создадим файл /etc/php5/mods-available/roundcube.ini, используя при его составлении информацию из файла /usr/share/roundcube/.htaccess:
upload_max_filesize=5M
;post_max_size=6M
;session.gc_maxlifetime=21600
;session.gc_divisor=500
;session.gc_probability=1
;mbstring.func_overload=0
В этот файл я вписал лишь те настройки, которые отличаются от дистрибутивных. Настройки сессии я не считаю столь важными, чтобы заменять ими стандартные, поэтому их я закомментировал. Также я закомментировал настройку post_max_size, потому что другое приложение использует большее значение. Из всех настроек я оставил только upload_max_filesize, зато закомментировал её в другом приложении, т.к. там её значение было меньше.

3. Настройка приложения

Настроим roundcube, прописав настройки в файл /etc/roundcube/main.inc.php:
$rcmail_config['default_host'] = 'tls://%n';
$rcmail_config['username_domain'] = '%d';
$rcmail_config['mail_domain'] = '%d';
$rcmail_config['smtp_server'] = 'tls://%n';
$rcmail_config['smtp_user'] = '%u';
$rcmail_config['smtp_pass'] = '%p';
$rcmail_config['smtp_helo_host'] = '';
$rcmail_config['force_https'] = true;
О настройках:
  • default_host - имя узла, выбираемое при входе в веб интерфейс. Можно указать список узлов, который будет отображаться в виде выпадающего меню. Можно использовать шаблоны: %n - использовать доменное имя из URL, %d - использовать доменное имя из URL без первой части, %s - использовать доменное имя, указанное после символа @ в логине пользователя. Можно указать префикс ssl:// или tls:// для использования защищённого соединения,
  • username_domain - автоматически добавлять домен к логинам пользователей. Можно задать ассоциативный массив для отображения доменного имени из URL в почтовый домен, можно использовать шаблоны: %h - имя IMAP-узла пользователя (что бы это ни значило), %n - доменное имя из URL, %d - доменное имя из URL без первой части, %z - доменное имя IMAP-узла без первой части,
  • mail_domain - доменное имя для формирования адресов новых пользователей. Правила такие же, как и для username_domain,
  • smtp_server - имя узла, выбираемое для отправки почты. Можно использовать шаблоны: %h - имя SMTP-узла пользователя (что бы это ни значило), %n - доменное имя из URL, %d - доменное имя из URL без первой части, %z - доменное имя SMTP-узла без первой части. Можно указать префикс ssl:// или tls:// для использования защищённого соединения,
  • smtp_user - если для отправки почты требуется аутентификация, то здесь можно указать имя пользователя или шаблон %u, чтобы имя пользователя бралось из веб-интерфейса,
  • smtp_pass - аналогично, если для отправки почты требуется аутентификация, то здесь можно указать пароль пользователя или шаблон %p, чтобы пароль пользователя брался из веб-интерфейса,
  • smtp_helo_host - подставлять в команду HELO/EHLO указанное имя узла. Если оставить строку пустой, то имя узла будет браться из переменной SERVER_NAME веб-сервера или же будет использоваться имя localhost,
  • force_https - настройка, предписывающая RoundCube переадресовывать пользователя на защищённую версию протокола HTTP - HTTPS.
4. Проверка работы

Теперь можно подключать оба файла к использованию:
# ln -s ../mods-available/roundcube.ini conf.d/30-roundcube.ini
# lighty-enable-mod roundcube
# /etc/init.d/lighttpd restart
И войти в веб-интерфейс Roundcube по ссылке http://mail.domain.tld:
Страница входа в Roundcube
5. Настройка плагинов

Из всех плагинов меня в первую очередь заинтересовали три:
  • Плагин password для смены пароля на почтовый ящик (находится в пакете roundcube-plugins),
  • Плагин acl для настройки IMAP ACL (находится в пакете roundcube-plugins),
  • Плагин dkimstatus для проверки DKIM-подписей полученных сообщений (находится в пакете roundcube-plugins-extra),
  • Плагин sieverules для управления правилами фильтрации Sieve на IMAP-сервере по протоколу ManageSieve (находится в пакете roundcube-plugins-extra).
5.1. Настройка плагина password

Для настройки плагина password впишем в файл /etc/roundcube/plugins/password/config.inc.php следующие настройки:
<?php
// Empty configuration for password
// See /usr/share/roundcube/plugins/password/config.inc.php.dist for instructions

$rcmail_config['password_driver'] = 'sql';
$rcmail_config['password_confirm_current'] = true;
$rcmail_config['password_minimum_length'] = 7;
$rcmail_config['password_db_dsn'] = 'mysql://roundcube:roundcube_password@localhost/postfixadmin';
$rcmail_config['password_query'] = 'UPDATE mailbox SET password=%c, modified=NOW() WHERE username=%u';
?>
И дадим пользователю roundcube права на изменение пароля:
INSERT INTO tables_priv(host, db, user, table_name, table_priv, column_priv) VALUES
('localhost', 'postfixadmin', 'roundcube', 'mailbox', '', 'Select,Update');

INSERT INTO columns_priv(host, db, user, table_name, column_name, column_priv) VALUES
('localhost', 'postfixadmin', 'roundcube', 'mailbox', 'username', 'Select'),
('localhost', 'postfixadmin', 'roundcube', 'mailbox', 'password', 'Update'),
('localhost', 'postfixadmin', 'roundcube', 'mailbox', 'modified', 'Update');

FLUSH PRIVILEGES;
Теперь включим использование плагина password, добавив его в настройку plugins в файле /etc/roundcube/main.inc.php:
$rcmail_config['plugins'] = array('password');
После этого в веб-интерфейсе Roundcube появится дополнительная вкладка для смены пароля:
Плагин password в Roundcube
5.2. Настройка плагина acl

У этого плагина, на мой взгляд, есть лишь одна настройка, заслуживающая внимания - acl_advanced_mode, с помощью которой можно включить более тонкую настройку IMAP ACL. Для её включения нужно вписать в файл /etc/roundcube/plugins/acl/config.inc.php следующую строку:
$rcmail_config['acl_advanced_mode'] = true;
Для включения самого плагина acl нужно добавить его в настройку plugins в файле /etc/roundcube/main.inc.php:
$rcmail_config['plugins'] = array('password', 'acl');
После добавления плагина в настройках папок появится новая вкладка Sharing:
Плагин acl в Roundcube
5.3. Настройка плагина dkimstatus

Плагин не требует настройки и для его включения нужно добавить его в настройку plugins в файле /etc/roundcube/main.inc.php:
$rcmail_config['plugins'] = array('password', 'acl', 'dkimstatus');
После его включения у каждого письма с правильной DKIM-подписью появится значок в виде галочки в зелёном кружке (пример письма, полученного от отправителя в Yandex-почте):
Плагин dkimstatus в Roundcube
5.4. Настройка плагина sieverules

В пакетах roundcube-pugins и roundcube-plugins-extra были найдены два плагина для настройки правил фильтрации почты на IMAP-сервере через протокол ManageSieve: managesieve и sieverules. Как оказалось, второй плагин был написан на основе первого и по сути заменяет его собой. Поэтому я решил настроить именно плагин sieverules.

Для настройки плагина sieverules скопируем файл /usr/share/roundcube/plugins/sieverules/config.inc.php.dist в файл /etc/roundcube/plugins/sieverules/config.inc.php. Нужно именно скопировать файл, т.к. при добавлении настроек в имеющийся пустой файл, плагин работает неправильно - выпадающий список действий оказывается пустым. Изменим в нём значения следующих настроек:
$rcmail_config['sieverules_host'] = '%n';
$rcmail_config['sieverules_port'] = 4190;
$rcmail_config['sieverules_usetls'] = TRUE;
Краткое описание изменённых настроек:
  • sieverules_host - задаёт сервер ManageSieve. Поддерживаются шаблоны: %h - имя IMAP-сервера, %n - имя сервера из URL, %d - доменное имя из URL без первой части.
  • sieverules_port - задаёт номер порта сервера ManageSieve. Ранее использовался TCP-порт с номером 2000, однако позже он был объявлен устаревшим и теперь используется TCP-порт с номером 4190.
  • sieverules_usetls - настройка задаёт использование защищённого соединения для связи с сервером ManageSieve.
Осталось включить использование плагина в настройках RoundCube, добавив имя плагина в настройку plugins в файле /etc/roundcube/main.inc.php:
$rcmail_config['plugins'] = array('password', 'acl', 'dkimstatus', 'sieverules');
После добавления плагина в настройках появляется вкладка "Фильтры":
Плагин sieverules в Roundcube
По умолчанию имеется только один набор правил, а доступ к прямому редактированию правил отключен - редактирование осуществляется при помощи веб-интерфейса плагина.

Настройка sieverules_multiplerules позволяет создавать несколько наборов правил, из которых активным может быть только одни набор.

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

Это была заключительная статья из серии статей о настройке почтовой системы.

воскресенье, 16 февраля 2014 г.

Дополнения Thunderbird/Icedove

Настройка серверной части почтовой системы была подробно рассмотрена в прошлых заметках Установка и настройка Postfixadmin, Установка и настройка Dovecot, Установка и настройка Postfix, OpenDKIM, ClamAV-Milter, Milter-Greylist и Настройка SSL/TLS в Postfix, Dovecot, Lighttpd.

На этот раз я немного отвлекусь от темы и опишу полезные дополнения к почтовому клиенту Thunderbird, известному в Debian под названием Icedove. Упомянуты будут как плагины, полезные для работы непосредственно с настроенной нами почтовой системой, так и другие, просто полезные, плагины.

1. Display Quota

Настроенный нами IMAP-сервер поддерживает квоты почтового ящика и умеет сообщать клиенту о текущем значении и использовании квоты.

Дополнение Display Quota отображает процент использования квоты в строке статуса и умеет оповещать о достижении указанного в настройка порога использования квоты.

Строка статуса с Display Quota

2. IMAP ACL Extension

IMAP-сервер, настройка которого была описана, позволяет пользователям почтовой системы предоставлять доступ к папкам в своих почтовых ящиках.

Дополнение IMAP-ACL-Extension позволяет задавать разрешения на доступ к почтовому ящику для других пользователей почтовой системы. После его подключения во вкладке "Совместное использование" свойств папки появляется кнопка "Set Permission".

Вкладка &lquot;Совместное использование&rquot; в диалоговом окне &lquot;Свойства папки&rquot;

3. DKIM Verifier

Настроенный нами SMTP-сервер добавляет DKIM-подпись к письмам, отправляемым его собственным пользователям. В то же время нашим пользователям тоже может быть полезно видеть результат проверки DKIM-подписей от других почтовых систем.

Дополнение DKIM Verifier добавляет в информацию о письме строчку с результатом проверки DKIM-подписи письма:

Демонстрация работы плагина DKIM Verifier

Плагин можно установить только в Icedove версии 17, которая есть в репозитории security.debian.org. Для использования этого репозитория нужно прописать в файл /etc/apt/sources.list одну из двух строк (или обе сразу):
deb http://security.debian.org wheezy/updates main
deb http://mirror.yandex.ru/debian-security wheezy/updates main
А затем обновить список пакетов и установить обновлённые пакеты, среди которых будет Icedove свежей версии:
# apt-get update
# apt-get upgrade
4. Sieve

Настроенный нами LDA из Dovecot позволяет производить сортировку полученной почты в соответствии со скриптами Sieve. Почтовый клиент по протоколу Manage Sieve может управлять Sieve-скриптами.

Для того, чтобы воспользоваться функционалом Sieve и Manage Sieve, можно воспользоваться дополнением с незамысловатым названием Sieve.

Пункты меню для входа в окно настройки подключения к ManageSieve и для настройки самих правил Sieve:

Пункты меню

Настройка подключения к ManageSieve:

Настройка ManageSieve

Список скриптов Sieve, имеющихся на сервере. Можно включить только один скрипт одновременно:

Список правил Sieve

Пример скрипта Sieve, перемещающий письмо для указанного получателя в отдельную папку (особенно удобно для сортировки писем с различных рассылок):

Скрипт Sieve

Описание синтаксиса правил можно найти в Википедии, на странице Sieve

5. ImportExportTools

Добавляет инструменты для импорта и экспорта сообщений и папок.

Демонстрация работы плагина ImportExportTools

6. Remove Duplicate Messages

Добавляет в контекстное меню папки функцию удаления дубликатов сообщений.

Демонстрация работы плагина Remove Duplicate Messages

В следующей заметке будет рассмотрена настройка почтового клиента RoundCube, позволяющего полноценно работать с почтовым IMAP-сервером через веб-интерфейс.

воскресенье, 9 февраля 2014 г.

Настройка SSL/TLS в Postfix, Dovecot, Lighttpd

Настройка SSL и TLS уже была вскользь упомянута в предыдущих заметках Установка и настройка Postfixadmin, Установка и настройка Dovecot и Установка и настройка Postfix, OpenDKIM, ClamAV-Milter, Milter-Greylist. В этой заметке я собираюсь раскрыть тему поподробнее. Учтите, что некоторые из описанных настроек я не тестировал, они приведены лишь для того, чтобы обозначить направление, в котором следует двигаться, если такие настройки понадобятся.

1. Подготовка сертификатов SSL/TLS

Сертификаты могут быть самоподписанными или подписанными удостоверяющим центром. Самоподписанные сертификаты обычно используются лишь для тестирования поддержки SSL/TLS в различных серверах и отладки настроек. На публичных серверах стоит использовать сертификаты, подписанные удостоверяющими центрами.

Услуги удостоверяющих центров, по моим меркам, обходятся довольно дорого, но некоторые удостоверяющие центры предоставляют и бесплатные ограниченные услуги для частных лиц. Мне известен только один такой удостоверяющий центр - StartSSL. Подробнее процедура получения такого сертификата описана, например, в статье Получаем бесплатный SSL сертификат или в заметке Бесплатный валидный (подписанный) SSL-сертификат через StartSSL. Перед получением сертификата нужно иметь настроенный почтовый сервер, чтобы иметь возможность подтвердить владение доменом.

2. Создание CA-сертификата (для самоподписания)

CA-сертификат - это сертификат центра сертификации (как бы тавтологично это ни звучало). Этим сертификатом подписываются все остальные сертификаты, используемые различными сервисами.

Воспользуемся скриптом, идущим в комплекте с пакетом openssl:
# /usr/lib/ssl/misc/CA.pl -newca
Перед созданием сертификата удостоверяющего центра скрипт задаст вам несколько вопросов. Нужно приготовиться предоставить следующую информацию:
  • Страна (Country)
  • Область (State or province)
  • Город (City or other municipal area)
  • Организация (Organization)
  • Подразделение (Organization unit)
  • Общепринятое имя (Common name)
  • Электронный адрес (Email address)
В процессе создания сертификата также нужно будет указать секретную фразу, которая будет использоваться каждый раз при подписании или отзыве удостоверенных сертификатов.

В поле «общепринятое имя» в данном случае нужно вписать название организации (или торговую марку, под которой она работает) или имя владельца. В случае создания сертификата сервера нужно указать его DNS-имя.

В текущем каталоге будет создан подкаталог demoCA, в котором будут созданы необходимые файлы.

После этого я дополнительно отредактировал файл конфигурации OpenSSL /etc/ssl/openssl.conf, указав в нём полный путь к каталогу с сертификатами удостоверяющего центра (в двух местах) и настройки срока годности вновь создаваемых сертификатов:
dir = /etc/ssl/demoCA
и
default_days = 3650
3. Создание сертификата сервера

Хотя удостоверяющий центр может сгенерировать и сертификат сервера, его можно сгенерировать самостоятельно:
# openssl req -new -nodes -keyout domain1.net.pem -out domain1.net.pem -days 3650
Generating a 2048 bit RSA private key
...........................................................................................+++
...........................................................................................................................................  ....................+++
writing new private key to 'domain1.net.pem'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:RU
State or Province Name (full name) [Some-State]:Bashkortostan Republic
Locality Name (eg, city) []:Ufa
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Vladimir Stupin
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:domain1.net
Email Address []:wheel69@yandex.ru

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
В этом случае при создании сертификата секретную фразу указывать не нужно, а в поле «Общеизвестное имя» нужно указать DNS-имя сервера.

В текущем каталоге будет создан файл domain1.net.pem с секретной частью сертификата.

4.1. Подписание сертификата сервера (самоподписание)

Для создания самоподписанного сертификата можно воспользоваться следующей командой:
# openssl ca -policy policy_anything -out domain1.net.pubilc.pem -infiles domain1.net.pem
Using configuration from /usr/lib/ssl/openssl.cnf
Enter pass phrase for /etc/ssl/ca/private/cakey.pem:
Check that the request matches the signature
Signature ok
Certificate Details:
        Serial Number: 14036232404122642274 (0xc2cab701208ea762)
        Validity
            Not Before: Feb  5 15:31:10 2014 GMT
            Not After : Feb  3 15:31:10 2024 GMT
        Subject:
            countryName               = RU
            stateOrProvinceName       = Bashkortostan Republic
            localityName              = Ufa
            organizationName          = Vladimir Stupin
            commonName                = domain1.net
            emailAddress              = wheel69@yandex.ru
        X509v3 extensions:
            X509v3 Basic Constraints: 
                CA:FALSE
            Netscape Comment: 
                OpenSSL Generated Certificate
            X509v3 Subject Key Identifier: 
                0B:DB:32:31:76:C8:F1:80:8E:2F:2E:70:8B:05:91:2A:91:69:AF:31
            X509v3 Authority Key Identifier: 
                keyid:B5:CB:D1:89:6A:E8:82:D2:D6:7C:A5:6C:13:88:EA:EE:D9:5F:8F:6E

Certificate is to be certified until Feb  3 15:31:10 2024 GMT (3650 days)
Sign the certificate? [y/n]:y


1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated

# mv domain1.net.pem domain1.net.private.pem
При подписании сертификата нужно будет указать секретную фразу из сертификата удостоверяющего центра (см. выше).

4.2. Подписание сертификата сервера (внешнее подписание)

В случае использования официального центра сертификации для подписания сертификата нужно следовать его инструкциям. Обычно для этого нужно скопировать из файла сертификата секцию CERTIFICATE REQUEST вместе с начальной и конечной строчками. Центр сертификации в ответ на запрос сгенерирует секцию CERTIFICATE, которую нужно вставить в private-файл после секции CERTIFICATE REQUEST.

После этого можно сгенерировать публичную часть сертификата:

# openssl x509 -in mail.stupin.su.pem -text > mail.stupin.su.public.pem
# mv domain1.net.pem domain1.net.private.pem
5. Подготовка сертификатов сервера к использованию

Расположим сертификаты так, чтобы они автоматически подхватились Dovecot'ом и настроим права доступа.

Чтобы локальные пользователи системы не получили доступ на чтение к приватной части сертификата и не смогли подменить публичную часть сертификата, нужно соответствующим образом выставить права доступа к файлам:
# chown root:root /etc/ssl/domain1.net.public.pem
# chmod u=rw,go=r /etc/ssl/domain1.net.public.pem

# chown root:root /etc/ssl/domain1.net.private.pem
# chmod u=rw,go= /etc/ssl/domain1.net.private.pem
6. Postfix

Postfix может выступать в роли SMTP-клиента, когда доставляет почту на другой почтовый сервер, и может выступать в роли SMTP-сервера, когда получает почту от другого сервера.

6.1. Настройка TLS в клиенте

Настроим шифрование и аутентификацию почтового сервера получателя, когда наш сервер будет пытаться отправить письмо по защищённому протоколу SMTP.

Сконвертируем pem-сертификат нашего удостоверяющего центра в формат crt и поместим в каталог для сертификатов доверенных центров авторизации:
# apt-get install ca-certificates
# mkdir /usr/share/ca-certificates/stupin.su
# openssl x509 -in /etc/ssl/demoCA/cacert.pem -out /usr/share/ca-certificates/stupin.su/cacert.crt
Теперь сгенерируем новый список сертификатов, которым будет доверять наша система:
# dpkg-reconfigure ca-certificates
В открывшемся окне нужно ответить «спрашивать» и отметить в списке наш сертификат. После этого будет сформирован новый файл /etc/ca-certificates.conf (нужно проверить, что в списке есть наш сертификат и в начале строчки нет восклицательного знака). pem-сертификаты будут помещены в каталог /etc/ssl/certs.

Добавим в файл /etc/postfix/main.cf следующие настройки:
# Настройка SMTP-клиента, отправляющего почту
smtp_tls_loglevel = 2
smtp_tls_CApath = /etc/ssl/certs
Осталось перезапустить сервер, чтобы настройки вступили в силу:
# /etc/init.d/postfix restart
6.2. Настройка TLS в сервере

Настраиваем шифрование с использованием ранее подготовленных SSL-сертификатов. Для этого добавим в файл /etc/postfix/main.cf следующие настройки:
# Настройка SMTP-сервера, принимающего почту
smtpd_use_tls = yes
smtpd_tls_key_file = /etc/ssl/domain1.net.private.pem
smtpd_tls_cert_file = /etc/ssl/domain1.net.public.pem
smtpd_tls_CApath = /etc/ssl/certs
smtpd_tls_loglevel = 2
smtpd_tls_received_header = yes
Осталось перезапустить сервер, чтобы настройки вступили в силу:
# /etc/init.d/postfix restart
6.3. Несколько сертификатов TLS на сервере

Postfix не имеет поддержки расширения SNI, потому что в SMTP клиент не может указать, к серверу с каким доменным именем он подключался. Соответственно, пока клиент не может этого сообщить, SMTP-сервер не может выбрать правильный сертификат. Для обслуживания почты из других доменов придётся обойтись настройкой MX-записи, указывающей на доменное имя сервера, которое он сообщает в команде HELO/EHLO.

Postfix также не имеет явных настроек для работы с разными сертификатами на разных IP-адресах. Однако, можно запустить несколько экземпляров сервера smtpd с разными настройками прослушиваемого IP-адреса, имени сервера и используемых сертификатов. Для этого можно попытаться задать в файле /etc/postfix/master.cf следующие настройки:
192.168.0.1:smtp inet  n  -        n        -        -        smtpd
  -o smtpd_tls_key_file=/etc/ssl/domain1.net.private.pem
  -o smtpd_tls_cert_file=/etc/ssl/domain1.net.public.pem
  -o myhostname=domain1.net
  -o mydomain=domain1.net
  -o myorigin=domain1.net

172.16.0.1:smtp inet  n  -        n        -        -        smtpd
  -o smtpd_tls_key_file=/etc/ssl/domain2.ru.private.pem
  -o smtpd_tls_cert_file=/etc/ssl/domain2.ru.public.pem
  -o myhostname=domain2.ru
  -o mydomain=domain2.ru
  -o myorigin=domain2.ru
Или можно воспользоваться новой возможностью Postfix - создать несколько экземпляров сервера. Подробнее об этом можно почитать на странице http://www.postfix.org/MULTI_INSTANCE_README.html

6.4. Оптимизация производительности

Настройка менеджера TLS-сессий описана в заметке Установка и настройка Postfix, OpenDKIM, ClamAV-Milter, Milter-Greylist в разделе «6. Оптимизация скорости работы Postfix».

7. Dovecot

При включении поддержки SSL нужно задать сертификат для использования по умолчанию. Включим поддержку SSL в файле /etc/dovecot/conf.d/10-ssl.conf:
ssl = yes
ssl_cert = </etc/ssl/domain1.net.public.pem
ssl_key = </etc/ssl/domain1.net.private.pem
И перезапустить Dovecot, чтобы новые настройки вступили в силу:
# /etc/init.d/dovecot restart
Dovecot может использовать как один сертификат, так и несколько. В случае использования нескольких сертификатов можно назначать отдельные сертификаты как на отдельные IP-адреса, на которых Dovecot будет ожидать подключения, так и на отдельные сервисы. Например, можно задать отдельные сертификаты для POP3 и для IMAP (хотя не ясно, какой в этом может быть смысл). Например, вот так:
local 192.168.0.1 {
  protocol imap {
    ssl_cert = </etc/ssl/dovecot/imap.domain1.net.public.pem
    ssl_key  = </etc/ssl/dovecot/imap.domain1.net.private.pem
  }

  protocol pop3 {
    ssl_cert = </etc/ssl/dovecot/pop.domain1.net.pubilc.pem
    ssl_key  = </etc/ssl/dovecot/pop.domain1.net.private.pem
  }
}

local 172.16.0.1 {
    ssl_cert = </etc/ssl/dovecot/domain2.ru.public.pem
    ssl_key  = </etc/ssl/dovecot/domain2.ru.private.pem
}
В примере выше указаны раздельные сертификаты для сервисов на первом IP-адресе и общий сертификат для сервисов на втором IP-адресе. Вместо IP-адресов можно указывать доменные имена, однако не впадайте в заблуждение - эти доменные имена не могут указывать на один и тот же IP-адрес. Перед использованием доменные имена решаются в IP-адреса, так что два домена, указывающих на один и тот же IP-адрес, породят две секции с одинаковым IP-адресом.

Использование раздельных сертификатов для отдельных IP-адресов и сервисов не избавляет от необходимости указывать сертификаты по умолчанию. Будьте внимательны!

Также Dovecot поддерживает расширение протокола SSL, которое называется Server Name Indication или, сокращённо, SNI. Если клиент поддерживает это расширение, то можно использовать разные сертификаты для разных доменных имён. Настройки, которые можно прописать при использовании SNI:
local_name domain1.net {
  ssl_cert = </etc/ssl/domain1.net.pubilc.pem
  ssl_key = </etc/ssl/domain1.net.private.pem
}

local_name domain2.ru {
  ssl_cert = </etc/ssl/domain2.ru.public.pem
  ssl_key = </etc/ssl/domain2.ru.private.pem
}
Более подробную информацию о настройке SSL в Dovecot можно найти на официальной wiki-странице: Dovecot SSL configuration. SNI поддерживается не всеми клиентами. Одним из клиентов с подтверждённой поддержкой SNI является Thunderbird в Linux.

8. Lighttpd

Для настройки SSL в веб-сервере Lighttpd достаточно включить модуль ssl:
# lighty-enable-mod ssl
B прописать используемый сертификат в файл /etc/lighttpd/conf-enabled/05-ssl.conf:
$SERVER["socket"] == "0.0.0.0:443" {
  ssl.engine  = "enable"
  ssl.pemfile = "/etc/ssl/vladimir.stupin.su.pem"

  ssl.cipher-list = "ECDHE-RSA-AES256-SHA384:AES256-SHA256:RC4:HIGH:!MD5:!aNULL:!EDH:!AESGCM"
  ssl.honor-cipher-order = "enable"
}
И перезапустить веб-сервер, чтобы его новые настройки вступили в силу:
# /etc/init.d/lighttpd restart
Как видно, в настройках проверяется совпадение с прослушиваемым IP-адресом и TCP-портом 443. Очевидно, что таким образом можно задать несколько SSL-сертификатов, каждый из которых будет использоваться при обращении клиента к определённому IP-адресу веб-сервера. Например, вот так:
$SERVER["socket"] == "192.168.0.1:443" {
  ssl.engine  = "enable"
  ssl.pemfile = "/etc/ssl/domain1.net.pem"

  ssl.cipher-list = "ECDHE-RSA-AES256-SHA384:AES256-SHA256:RC4:HIGH:!MD5:!aNULL:!EDH:!AESGCM"
  ssl.honor-cipher-order = "enable"
}

$SERVER["socket"] == "172.16.0.1:443" {
  ssl.engine  = "enable"
  ssl.pemfile = "/etc/ssl/domain2.ru.pem"

  ssl.cipher-list = "ECDHE-RSA-AES256-SHA384:AES256-SHA256:RC4:HIGH:!MD5:!aNULL:!EDH:!AESGCM"
  ssl.honor-cipher-order = "enable"
}
Однако, таким образом можно задать только один сертификат для одного IP-адреса. Если же на одном IP-адресе обслуживается несколько доменов, то можно либо прописать в этот сертификат доменные имена всех необходимых сайтов, либо воспользоваться поддержкой SNI.

Веб-сервер Lighttpd поддерживает SNI начиная с версии 1.4.24, в случае если установлен OpenSSL версии 0.9.8f или выше. Для задания отдельных сертификатов для отдельных доменов можно воспользоваться условными секциями, меняя внутри них используемый сертификат:
$HTTP["host"] == "domain1.net" {
  ssl.pemfile = "/etc/ssl/domain1.net.pem"
}

$HTTP["host"] == "domain2.ru" {
  ssl.pemfile = "/etc/ssl/domain2.ru.pem"
}
Для того, чтобы принудительно использовать SSL на определённых сайтах, можно вписать в файл /etc/lighttpd/conf-enabled/05-ssl.conf следующую условную секцию:
$HTTP["host"] =~ "^domain(1\.net|2\.ru)$" {
  url.redirect = (".*" => "https://%0$0")
}
Стоит отметить, что сайты должны быть готовы к подобной переадресации. Например, во всех внутренних ссылках на сайте стоит убрать спецификацию протокола http. Все внутренние ссылки сайта должны быть либо относительными, либо начинаться с двух косых черт.

Продолжение следует...

воскресенье, 2 февраля 2014 г.

Установка и настройка Postfix, OpenDKIM, ClamAV-Milter, Milter-Greylist

Продолжение заметок Установка и настройка Postfixadmin и Установка и настройка Dovecot. В этой заметке мы настроим MTA и его обвязку. В качестве альтернативы Postfix можно воспользоваться Exim, настройка которого описана тут: Настройка Exim

1. Установка Postfix

Для работы Postfix понадобится поставить следующие пакеты:
# apt-get install postfix postfix-mysql
2. Базовая настройка Postfix

Выполним базовую настройку Postfix, вписав в файл /etc/postfix/main.cf следующее содержимое:
# Настраиваем имя почтового сервера и его домен по умолчанию
myhostname = mail.domain.tld
mydomain = domain.tld
myorigin = domain.tld
mydestination = $myhostname, localhost.$mydomain, localhost
 
# Ожидаем подключения на всех интерфейсах и только по IPv4
inet_protocols = ipv4
inet_interfaces = all
 
# Я не доверяю даже локальным отправителям, поэтому любой,
# кто захочет отправить письмо наружу, должен будет пройти аутентификацию
mynetworks = 
 
# Настройка уведомлений администратора об ошибках
notify_classes = resource, software, protocol, policy
 
# Настройка ограничений прав пользователя для транспорта virtual
virtual_minimum_uid = 120
virtual_uid_maps = static:120
virtual_gid_maps = static:120
 
# Настройка использования файла пересылок
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
 
local_recipient_maps = $alias_maps
 
# Максимальный размер принимаемого письма
message_size_limit = 31457280
 
# Ограничения на этапе установке подключения
smtpd_client_restrictions =
  # Разрешить клиентов из доверенных сетей
  permit_mynetworks,
  # Разрешить клиентов, прошедших аутентификацию
  permit_sasl_authenticated,
  # Отклонять клиентов, у которых доменное имя из PTR-записи
  # не решается в тот же IP по A-записи
  reject_unknown_client_hostname
 
# Ограничения на этапе команды HELO/EHLO
smtpd_helo_restrictions =
  permit_mynetworks,
  permit_sasl_authenticated,
  # Отклонять клиентов, использующих неправильный синтаксис доменного имени в HELO
  reject_invalid_helo_hostname,
  # Отклонять клиентов, указывающих в HELO не полное доменное имя
  reject_non_fqdn_helo_hostname,
  # Отклонять клиентов, DNS-имя из HELO которых не имеет A- или MX-записи
  reject_unknown_helo_hostname
 
# Отклонять клиентов, не использовавших команду HELO/EHLO
smtpd_helo_required = yes
 
# Ограничения на этапе команды MAIL FROM
smtpd_sender_restrictions =
  # Отклонять почту от отправителей с неполным доменным именем
  reject_non_fqdn_sender,
  # Отклонять почту от отправителей из несуществующих доменов
  reject_unknown_sender_domain,
  permit_mynetworks,
  permit_sasl_authenticated

# Ограничения на этапе команды RCPT TO
smtpd_recipient_restrictions =
  # Отклонять почту для получателей с неполным доменным именем
  reject_non_fqdn_recipient,
  # Отклонять почту для получателей в несуществующем домене
  reject_unknown_recipient_domain,
  permit_mynetworks,
  permit_sasl_authenticated,
  # Запретить отправлять почту в домены, которые мы не обслуживаем
  reject_unauth_destination,
  # Отклонять почту для получателей, которых у нас нет
  reject_unlisted_recipient
3. Интеграция Postfix и Postfixadmin

Добавляем пользователя postfix для доступа к базе данных:
USE mysql;
 
INSERT INTO user(user, password, host) VALUES('postfix', PASSWORD('postfix_password'), 'localhost');
 
FLUSH PRIVILEGES;
Даём пользователю postfix доступ к таблице ящиков, доменов, псевдонимов, псевдонимов доменов и квот:
USE mysql;
 
INSERT INTO tables_priv(host, db, user, table_name, table_priv, column_priv) VALUES
('localhost', 'postfixadmin', 'postfix', 'alias', '', 'Select'),
('localhost', 'postfixadmin', 'postfix', 'alias_domain', '', 'Select'),
('localhost', 'postfixadmin', 'postfix', 'mailbox', '', 'Select'),
('localhost', 'postfixadmin', 'postfix', 'domain', '', 'Select'),
('localhost', 'postfixadmin', 'postfix', 'quota2', '', 'Select');
 
INSERT INTO columns_priv(host, db, user, table_name, column_name, column_priv) VALUES
('localhost', 'postfixadmin', 'postfix', 'alias', 'goto', 'Select'),
('localhost', 'postfixadmin', 'postfix', 'alias', 'address', 'Select'),
('localhost', 'postfixadmin', 'postfix', 'alias', 'active', 'Select');
 
INSERT INTO columns_priv(host, db, user, table_name, column_name, column_priv) VALUES
('localhost', 'postfixadmin', 'postfix', 'alias_domain', 'target_domain', 'Select'),
('localhost', 'postfixadmin', 'postfix', 'alias_domain', 'alias_domain', 'Select'),
('localhost', 'postfixadmin', 'postfix', 'alias_domain', 'active', 'Select');
 
INSERT INTO columns_priv(host, db, user, table_name, column_name, column_priv) VALUES
('localhost', 'postfixadmin', 'postfix', 'mailbox', 'maildir', 'Select'),
('localhost', 'postfixadmin', 'postfix', 'mailbox', 'username', 'Select'),
('localhost', 'postfixadmin', 'postfix', 'mailbox', 'active', 'Select'),
('localhost', 'postfixadmin', 'postfix', 'mailbox', 'quota', 'Select');
 
INSERT INTO columns_priv(host, db, user, table_name, column_name, column_priv) VALUES
('localhost', 'postfixadmin', 'postfix', 'domain', 'domain', 'Select'),
('localhost', 'postfixadmin', 'postfix', 'domain', 'backupmx', 'Select'),
('localhost', 'postfixadmin', 'postfix', 'domain', 'active', 'Select');
 
INSERT INTO columns_priv(host, db, user, table_name, column_name, column_priv) VALUES
('localhost', 'postfixadmin', 'postfix', 'quota2', 'username', 'Select'),
('localhost', 'postfixadmin', 'postfix', 'quota2', 'bytes', 'Select');
 
FLUSH PRIVILEGES;
Подготовим файлы SQL-карт, которыми будет пользоваться Postfix для получения различной информации из базы данных. Все файлы карт создаются в каталоге /etc/postfix/sql. Перед созданием файлов создаём каталог:
# mkdir /etc/postfix/sql
Создаём файл /etc/postfix/sql/domains.cf, в котором содержится SQL-запрос для получения списка активных доменов, для которых осуществляется приём почты:
user = postfix
password = postfix_password
hosts = 127.0.0.1
dbname = postfixadmin

query = SELECT domain
        FROM domain
        WHERE domain = '%s'
          AND backupmx = 0
          AND active = 1
Создаём файл /etc/postfix/sql/backup_domains.cf, в который поместим SQL-запрос, извлекающий список активных доменов, для которых наш почтовый сервер является резервным:
user = postfix
password = postfix_password
hosts = 127.0.0.1
dbname = postfixadmin

query = SELECT domain
        FROM domain
        WHERE domain = '%s'
          AND backupmx = 1
          AND active = 1
Почтовый сервер будет принимать почту для этих доменов, не складывая в какой-либо почтовый ящик, а размещая письма в очереди на отправку. При первой возможности он перешлёт её почтовому серверу, имеющему в DNS запись MX с меньшим числом, то есть - с большим приоритетом. Сервер с самым высоким приоритетом поместит письма в почтовые ящики получателей.

Создаём файл /etc/postfix/sql/alias.cf, содержащим SQL-запрос для извлечения списка активных пересылок:
user = postfix
password = postfix_password
hosts = 127.0.0.1
dbname = postfixadmin

query = SELECT goto
        FROM alias
        WHERE address = '%s'
          AND active = 1
Когда почта направляется на адрес пересылки, Postfix подменит адрес доставки на адрес, указанный в этой таблице. Postfix предпримет несколько попыток замены, до тех пор, пока SQL-запрос не перестанет возвращать результаты или результат ничем не будет отличаться от исходного адреса. Таким образом можно создать цепочку пересылок, однако это не приветствуется, поскольку при этом Postfix будет выполнять больше SQL-запросов к базе данных и таким образом можно случайно зациклить цепочку. Postfix имеет ограничение на максимальную длину цепочки, так что слишком длинные или зацикленные цепочки работать не будут.

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

Создаём файл /etc/postfix/sql/alias_domain.cf, в который поместим SQL-запрос для извлечения активных пересылок доменов:
user = postfix
password = postfix_password
hosts = 127.0.0.1
dbname = postfixadmin

query = SELECT alias.goto
        FROM alias_domain
        JOIN alias ON alias.address = CONCAT('%u', '@', alias_domain.target_domain)
          AND alias.active = 1
        WHERE alias_domain.alias_domain = '%d'
          AND alias_domain.active = 1
Пересылки для доменов действуют следующим образом: Если в домене получателя есть почтовый ящик или пересылка, локальная часть адреса которого совпадает с локальной частью адреса получателя, то доменная часть адреса получателя подменяется на указанную в пересылке.

Например, если есть доменная пересылка domain.tld -> domain.com и на почтовом сервере есть адрес box@domain.com, то при отправке письма на адрес box@domain.tld, его получателем будет адрес box@domain.com. К этому адресу применимы обычные пересылки, то есть реальным получателем этого письма может быть и другой ящик, для которого пересылка создана явным образом, например box@domain.tld -> boxer@domain.ru.

Создаём файл /etc/postfix/sql/alias_domain_catchall.cf, который содержит SQL-запрос для пересылок доменов, захватывающих письма для любого ящика в домене:
user = postfix
password = postfix_password
hosts = 127.0.0.1
dbname = postfixadmin

query = SELECT alias.goto
        FROM alias_domain
        JOIN alias ON alias.address = CONCAT('@', alias_domain.target_domain)
          AND alias.active = 1
        WHERE alias_domain.alias_domain = '%d'
          AND alias_domain.active = 1
Если для получателя не найдена явная пересылка с адреса на адрес и не найдена пересылка из домена в другой домен с такой же локальной частью адреса, то это правило перехватит почту для любого другого ящика в домене и перешлёт её на указанный ящик.

Например, почта направляется в ящик office@domain.tld, есть пересылка из домена domain.tld в домен domain.com, но ящика или пересылки с именем office@domain.com нет, но есть пересылка из домена domain.tld на ящик info@domain.com, то почта для office@domain.tld попадёт в ящик info@domain.com. Довольно сложное объяснение. Проще - такие пересылки захватывают почту для не существующих в домене адресов и перенаправляют её на указанный адрес.

Создаём файл /etc/postfix/sql/mailbox.cf, в который поместим запрос, возвращающий путь к каталогу активного почтового ящика:
user = postfix
password = postfix_password
hosts = 127.0.0.1
dbname = postfixadmin

query = SELECT maildir
        FROM mailbox
        WHERE username = '%s'
          AND active = 1
Создаём файл /etc/postfix/sql/alias_domain_mailbox.cf, в который поместим SQL-запрос для извлечения каталога почтового ящика с пересылкой из другого домена:
user = postfix
password = postfix_password
hosts = 127.0.0.1
dbname = postfixadmin

query = SELECT mailbox.maildir
        FROM alias_domain
        JOIN mailbox ON mailbox.username = CONCAT('%u', '@', alias_domain.target_domain)
          AND mailbox.active = 1
        WHERE alias_domain.alias_domain = '%d'
          AND alias_domain.active = 1
Смысл этого файла совпадает со смыслом файла /etc/postfix/sql/alias_domain.cf и мне не совсем понятно, для чего нужен этот файл. Возможно для того, чтобы можно было отправлять почту с ящика в другом домене, успешно авторизуясь на SMTP-сервере.

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

Если вы настраивали Dovecot с поддержкой квот, то понадобится также создать файл /etc/postfix/sql/mailbox_limit.cf для проверки превышения квоты получателем:
user = postfix
password = postfix_password
hosts = 127.0.0.1
dbname = postfixadmin

query = SELECT '452 Mailbox is over quota'
        FROM mailbox
        JOIN quota2 ON quota2.username = mailbox.username
          AND mailbox.quota - quota2.bytes <= 0
        WHERE mailbox.username = '%s'
          AND mailbox.active = 1
Этого SQL-запроса в Postfixadmin нет, я добавил его сам. Насколько я знаю, существует некий патч к транспорту virtual из Postfix, который добавляет в него поддержку квот. Мы, однако, будем использовать транспорт dovecot, поэтому патчи нам не нужны. Однако, если не добавить в Postfix правила, использующего приведённый выше запрос, то при превышении квоты почтового ящика происходит неприятная ситуация: Postfix письмо принимает, но не может передать его Dovecot, поскольку тот отказывается его принять, ссылаясь на превышение квоты. В результате письмо продолжает болтаться в почтовой очереди Postfix, чего нам не нужно, т.к. потенциальные злоумышленники могут забить сначала квоту почтового ящика, а затем и очередь Postfix. Вместо этого мы добавим в Postfix правило, которое будет сообщать о временной ошибке доставки почты, если соответствующий ящик переполнен. Отправитель же может поступить по собственному усмотрению - повторять периодические попытки отправить письмо.

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

Выставим права доступа к файлам SQL-карт, чтобы потенциальный злоумышленник, получивший локальный доступ к системе, не смог получить список почтовых ящиков:
# cd /etc/postfix
# chown -R postfix:postfix sql
# chmod u=rwx,g=rx,o= sql
# cd sql
# chmod u=rw,g=r,o= *
Теперь осталось добавить использование SQL-карт в Postfix. Для этого вписываем в файл /etc/postfix/main.cf следующие строки:
virtual_mailbox_domains = proxy:mysql:/etc/postfix/sql/domains.cf
relay_domains = proxy:mysql:/etc/postfix/sql/backup_domains.cf
virtual_alias_maps =
   mysql:/etc/postfix/sql/alias.cf,
   mysql:/etc/postfix/sql/alias_domain.cf,
   mysql:/etc/postfix/sql/alias_domain_catchall.cf
virtual_mailbox_maps =
   mysql:/etc/postfix/sql/mailbox.cf,
   mysql:/etc/postfix/sql/alias_domain_mailbox.cf
Также найдём в файле /etc/postfix/main.cf правило smtpd_recipient_restrictions и добавим проверку квот перед разрешением отправлять почту для наших сетей и аутентифицированных пользователей:
smtpd_recipient_restrictions =
  reject_non_fqdn_recipient,
  reject_unknown_recipient_domain,
  check_recipient_access proxy:mysql:/etc/postfix/pasql/mailbox_limit.cf,
  permit_mynetworks,
  permit_sasl_authenticated,
  reject_unauth_destination,
  reject_unlisted_recipient
Уже в таком виде мы получим Postfix, который сможет принимать почту для получателей в наших доменах. Правда, в таком виде он не умеет пересчитывать использование квот почтовых ящиков в таблице quota2 при получении нового письма. Отправить письмо наружу тоже не получится - он не примет письмо без аутентификации клиента, а механизмы аутентификации ещё не были настроены.

4. Интеграция Postfix и Dovecot

Сейчас мы добавим пересчёт квот при получении нового письма и добавим механизмы аутентификации. В файл /etc/postfix/main.cf нужно добавим настройки для использования Dovecot как LDA и SASL-провайдера:
# Dovecot LDA
virtual_transport = dovecot
dovecot_destination_recipient_limit = 1
virtual_mailbox_base = /home/vmail

# Dovecot SASL
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes
Если Postfix получит письмо для получателя, настроенного через параметры virtual_*, он попытается воспользоваться транспортом virtual, для того чтобы поместить письмо в ящик получателя. Вместо LDA virtual, имеющимся в составе Postfix, мы будем использоваться LDA, имеющимся в составе Dovecot. Он умеет пересчитывать квоты в таблице quota2.

Для SMTP-аутентификации клиентов будет использоваться SASL-сервис из состава Dovecot. Если вы пропустили настройку этого сервиса Dovecot, стоит заглянуть в описание настройки Dovecot и настроить его сейчас.

Осталось вписать в файл /etc/postfix/master.cf агент локальной доставки (LDA) Dovecot:
dovecot   unix  -       n       n       -       -       pipe
  flags=DRhu user=vmail:vmail argv=/usr/lib/dovecot/deliver -f ${sender} -d ${recipient}
Теперь можно запустить MTA:
# /etc/init.d/postfix restart
Если есть подозрение, что учтённое использование квоты не соответствует действительности, можно пересчитать использование квот для всех ящиков при помощи следующей команды:
# doveadm quota recalc -A
5. Настройка SSL/TLS

Настраиваем шифрование с использованием ранее подготовленных SSL-сертификатов. Для этого добавим в файл /etc/postfix/main.cf следующие настройки:
# Настройка SMTP-сервера, принимающего почту
smtpd_use_tls = yes
smtpd_tls_key_file = /etc/ssl/mail_private.pem
smtpd_tls_cert_file = /etc/ssl/mail_public.pem
smtpd_tls_CApath = /etc/ssl/certs
smtpd_tls_loglevel = 2
smtpd_tls_received_header = yes
 
# Настройка SMTP-клиента, отправляющего почту
smtp_tls_loglevel = 2
smtp_tls_CApath = /etc/ssl/certs
6. Оптимизация скорости работы Postfix

Демоны, входящие в состав Postfix, периодически перезапускаются. Это касается и демонов smtp и smtpd. Пока они работают, каждый из них поддерживает в своей памяти сеансовые ключи для всех серверов или клиентов, с которыми были установлены защищённые соединения.

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

Чтобы ключи хранились в кэше и не пересчитывались каждый раз, можно включить использование менеджера сеансовых ключей tlsmgr, входящего в состав Postfix. Для этого впишем в файл /etc/postfix/main.cf файл, в котором размещаются сеансовые ключи и зададим время кэширования:
smtpd_tls_session_cache_database = sdbm:/var/lib/postfix/tlsmgr_smtpd.db
smtpd_tls_session_cache_timeout = 3600s
 
smtp_tls_session_cache_database = sdbm:/var/lib/postfix/tlsmgr_smtp.db
smtp_tls_session_cache_timeout = 3600s
Стоит отметить, что каталог с сеансовыми ключами стоит размещать вне chroot-окружения Postfix, поскольку потенциальный злоумышленник, взломавший демона, работающего в chroot-окружении, сможет подменить файлы кэша, получив таким образом возможность, например, принять почту от не аутентифицированного отправителя.

Как уже было сказано, процессы Postfix периодически перезапускаются. При каждом перезапуске каждый процесс устанавливает собственное подключение к базе данных. Чтобы уменьшить одновременное количество подключений к базе данных и снизить частоту переподключений, можно настроить специальный прокси-сервер. Он будет принимать соединения от демонов Postfix и выполнять запросы, пользуясь небольшим количество постоянных подключений к базе данных.

Для настройки использования прокси нужно в файле /etc/postfix/main.cf перед каждой используемой картой mysql указать через двоеточие текст proxy:
virtual_mailbox_domains = proxy:proxy:mysql:/etc/postfix/sql/domains.cf
relay_domains = proxy:proxy:mysql:/etc/postfix/sql/backup_domains.cf
virtual_alias_maps =
   proxy:mysql:/etc/postfix/sql/alias.cf,
   proxy:mysql:/etc/postfix/sql/alias_domain.cf,
   proxy:mysql:/etc/postfix/sql/alias_domain_catchall.cf
virtual_mailbox_maps =
   proxy:mysql:/etc/postfix/sql/mailbox.cf,
   proxy:mysql:/etc/postfix/sql/alias_domain_mailbox.cf
 
...
 
smtpd_recipient_restrictions =
  check_recipient_access proxy:mysql:/etc/postfix/sql/mailbox_limit.cf,
Также следует указать демону-прокси список обслуживаемых им карт, чтобы он прочитал их до перехода в chroot-окружение. Для этого добавим в файл /etc/postfix/main.cf следующие опции:
proxy_read_maps =
  proxy:mysql:/etc/postfix/pasql/domains.cf,
  proxy:mysql:/etc/postfix/pasql/backup_domains.cf,
  proxy:mysql:/etc/postfix/pasql/alias_domain.cf,
  proxy:mysql:/etc/postfix/pasql/alias_domain_mailbox.cf,
  proxy:mysql:/etc/postfix/pasql/alias_domain_catchall.cf,
  proxy:mysql:/etc/postfix/pasql/alias.cf,
  proxy:mysql:/etc/postfix/pasql/mailbox.cf,
  proxy:mysql:/etc/postfix/pasql/mailbox_limit.cf
Осталось перезапустить Postfix, чтобы настройки вступили в силу:
# /etc/init.d/postfix restart
7. Настройка ClamAV-Milter

На мой взгляд, защита от вирусов является обязательным компонентом почтовой системы. Отсутствие проверки на вирусы говорит о низкой квалификации системного администратора. Наиболее доступным, простым в настройке и ставшим стандартом де-факто для проверки почты в мире юникс-систем, считается антивирус ClamAV, который мы и настроим.

Устанавливаем демон ClamAV для проверки файлов на вирусы и демон ClamAV-Milter, работающий по протоколу Milter и предназначенный специально для проверки на наличие вирусов писем:
# apt-get install clamav-milter clamav-daemon
Сразу же обновляем антивирусную базу:
# freshclam
Настройка для демона ClamAV не требуется. Настроим ClamAV-Milter - нужно указать такое расположение Milter-сокета, которое было бы доступно для почтовой системы внутри chroot-окружения в каталоге /var/spool/postfix. Я указал в файле /etc/clamav/clamav-milter.conf такую строчку:
MilterSocket /var/spool/postfix/clamav-milter
Теперь настроим Postfix на использование этого сокет-файла. Для этого в файле /etc/postfix/main.cf укажем в списке Milter-фильтров настроенный сокет:
milter_default_action = accept
milter_protocol = 2
 
smtpd_milters = unix:/clamav-milter
non_smtpd_milters = unix:/clamav-milter
Перезапустим ClamAV-Milter и Postfix, чтобы настройки вступили в силу:
# /etc/init.d/clamav-milter restart
# /etc/init.d/postfix restart
Осталось проверить, что антивирусная система используется. Для этого создадим специально предназначенный для таких целей тестовый файл EICAR:
$ echo -n 'X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*' > eicar.txt
И попробуем его отправить во вложении с какого-нибудь почтового ящика почтовой системы на тот же ящик. Если письмо не пришло, значит антивирусная система работает. Для полной уверенности можно ещё заглянуть в журнал почтовой системы /var/log/mail.log, где должна появиться строчка вида:
Dec 29 17:04:46 mail postfix/cleanup[2035]: 770B685287: milter-hold: END-OF-MESSAGE from localhost[127.0.0.1]: milter triggers HOLD action; from=<box@domain.tld> to=<box@domain.tld> proto=ESMTP helo=<computer.domain.tld>
Чтобы выяснить, какой конкретно вирус был обнаружен, можно обратиться к журналу демона ClamAV в файле /var/log/clamav/clamav.log, где должна быть запись, относящаяся примерно к тому же времени и содержащая текст следующего вида:
Sun Dec 29 17:04:46 2013 -> fd[10]: Eicar-Test-Signature(4017e0393a0297fc376f7be69ad6a1b0:881) FOUND
8. Настройка OpenDKIM

DKIM - DomainKeys Identified Mail - это цифровая подпись, которую почтовый сервер добавляет к письмам от отправителей из обслуживаемых им доменов. Для этого сервер использует секретную часть ключа, которая известна только ему. Получатель может проверить подпись письма при помощи публичной части ключа, доступной через DNS-запись домена отправителя.

Нужно понимать, что DKIM не защищает от подделки отправителя и не может являться гарантией того, что письмо является полезным и безопасным, т.е. не содержит спама и вирусов. DKIM лишь удостоверяет, что почтовый сервер уполномочен владельцем домена на обслуживание почты, исходящей из этого домена. Спамеры вполне могут приобрести домен, настроить DNS и почтовый сервер для отправки писем с DKIM-подписью. Однако это требует финансовых затрат, а источник спама при этом легко идентифицировать и заблокировать. Спамеры же стараются зарабатывать деньги, оставаясь анонимными. Поэтому письмо, имеющее правильную DKIM-подпись, можно с высокой степенью достоверности считать полезным и безопасным.

Добавление DKIM-подписей к письмам позволяет повысить доверие других почтовых систем к нашим письмам. Проверка DKIM-подписей - это отдельная тема, связанная с фильтрацией писем после их приёма. Перед настройкой DKIM стоит воспользоваться другими средства для повышения доверия к почте от нашего сервера, которые проще в настройке и чаще используются, - это настройка PTR- и SPF-записей:
  1. PTR-запись для IP-адреса сервера должна указывать на его имя, которое он сообщает в команде HELO/EHLO. A-запись для этого имени должна указывать на этот же IP-адрес. Наличие правильной PTR-записи по стандарту не обязательно, но большинство почтовых систем его проверяют, поэтому выполнение этого требования весьма желательно.
  2. SFP-запись - это TXT-запись следующего вида:
    domain.tld. IN TXT "v=spf1 +mx ~all"
    Если указанный домен обслуживается одним почтовым сервером, этой записи достаточно. В более сложных случаях следует обратиться к документу проекта Sender Policy Framework, описывающему синтаксис SFP-записи - SPF Record Syntax. Стоит также прочесть о наиболее частых ошибках, допускаемых при создании SFP-записи - Common mistakes.

Приступим к настройке OpenDKIM для добавления подписей к почте из наших доменов. Настройка производится в соответствии со статьёй OpenDKIM + Postfix = просто с небольшими отличиями - я использую сокет-файл.

Устанавливаем OpenDKIM:
# apt-get install opendkim opendkim-tools
Готовим каталог для DKIM-ключей:
# mkdir /etc/postfix/dkim/
# cd /etc/postfix/dkim/
Генерируем ключи для домена domain.tld:
# opendkim-genkey -D /etc/postfix/dkim/ -d domain.tld -s mail
# mv mail.private mail.domain.tld.private
# mv mail.txt mail.domain.tld.txt
Далее можно сгенерировать ключи для других доменов, обслуживаемых нашей почтовой системой.

Создаём таблицы ключей для каждого из доменов в файле /etc/postfix/dkim/keytable:
mail._domainkey.domain.tld domain.tld:mail:/etc/postfix/dkim/mail.domain.tld.private
Создаём в файле /etc/postfix/dkim/signingtable таблицу, задающую ключи для доменов. В конце файла можно указать ключ для подписи писем из тех доменов, для которых ключ не указан явным образом:
domain.tld mail._domainkey.domain.tld
* mail._domainkey.stupin.su
Меняем группу и права доступа к файлам:
# cd /etc/postfix/dkim/
# chown root:opendkim *
# chmod u=rw,g=r,o= *
В файле /etc/opendkim.conf прописываем следующую конфигурацию:
# Настройки журналирования и отладки
Syslog                yes
SyslogSuccess         yes
LogWhy                yes
X-Header              yes
 
# Меняем для того, чтобы Postfix мог писать в сокет
UMask                 000
Canonicalization      relaxed/relaxed
 
# Sign и Verify - подписывать и проверять подпись
Mode                  sv
KeyTable              file:/etc/postfix/dkim/keytable
SigningTable          file:/etc/postfix/dkim/signingtable
OversignHeaders       From
Сокет, создаваемый OpenDKIM, должен быть доступен внутри chroot-окружения Postfix, внутри /var/spool/postfix/. Однако этот каталог принадлежит Postfix и поэтому пользователь opendkim не сможет создать в нём сокет-файл. Чтобы обойти это ограничение мы самостоятельно создадим внутри chroot-окружения каталог, к которому будет иметь доступ пользователь opendkim:
# mkdir /var/spool/postfix/opendkim
# chown opendkim:opendkim /var/spool/postfix/opendkim
В файле /etc/defaults/opendkim прописываем настройки сокета, который будет использоваться Postfix'ом:
SOCKET="local:/var/spool/postfix/opendkim/socket"
Содержимое файла /etc/postfix/dkim/mail.domain.tld.txt и файлов для других доменов в соответствующие зоны DNS.

В файл конфигурации Postfix /etc/postfix/main.cf, в настройки smtpd_milters и non_smtpd_milters добавляем новый сокет-файл:
milter_default_action = accept
milter_protocol = 2
 
smtpd_milters = unix:/clamav-milter, unix:/opendkim/socket
non_smtpd_milters = unix:/clamav-milter, unix:/opendkim/socket
Этот сокет-файл должен быть указан в конце списка, чтобы OpenDKIM подписывал уже готовое письмо, в которое больше не будет добавляться дополнительных заголовков.

Курсивом отмечен Unix-сокет ClamAV-Milter, который был настроен в предыдущем разделе. Если вы не настраивали его, здесь их тоже не будет. Для настройки OpenDKIM достаточно лишь добавить Unix-сокеты, отмеченные жирным шрифтом.

Осталось перезапустить демонов OpenDKIM и Postfix, чтобы настройки вступили в силу:
# /etc/init.d/opendkim restart
# /etc/init.d/postfix restart
Всё готово, можно проверять. Попробовал отправить тестовое письмо на почтовый ящик в Yandex-почте, в почтовом ящике при открытии этого письма увидел следующую картинку:


9. Настройка Milter-Greylist

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

Частично мы уже настроили проактивную фильтрацию на этапе настройки Postfix. Он проверяет правильность имени почтовой системы, которым она представляется в команде HELO/EHLO, проверяет существование домена отправителя и домена получателя. Рассмотрим другие средства:
  1. RDNSBL - Reverse DNS Black Lists - чёрные списки адресов. Почтовый сервер формирует DNS-запрос, используя доменное имя чёрного списка и IP-адрес отправителя, который хочет передать нам почту. Если DNS-запрос завершится успешно, значит IP-адрес имеется в этом списке. Почтовый сервер может отклонить почту, если IP-адрес отправителя есть в чёрном списке. На мой взгляд, этот способ в чистом виде использовать не стоит, потому что у каждого проекта, ведущего чёрные списки, могут быть разные политики добавления и удаления. В некоторые чёрные списки легко попасть, но практически невозможно из них выбраться.
  2. Тарпиттинг - задержка, которую выдерживает почтовый сервер, перед тем как ответить клиенту. Большинство рассыльщиков спама стараются разослать как можно больше писем, поэтому обычно им некогда ждать и они отключаются от сервера получателя, не дождавшись ответа. Обычно задержка составляет 5-20 секунд.
  3. Встречная проверка отправителя. Почтовый сервер получателя пытается инициировать отправку письма на адрес отправителя. Результат проверки становится ясным до отправки тела письма, в этот момент почтовый сервер завершает сеанс и использует результат проверки для того, чтобы принять или отклонить письмо. Для проверки используется пустой адрес отправителя.

    Программы для рассылки спама обычно не готовы к прохождению такой проверки, поэтому такой способ проверки может помочь защититься от спама. Однако такая проверка может вызывать проблемы, если два сервера проверяют наличие отправителей друг на друге, но при этом один из них откажется принять почту на пустой адрес. Также могут возникнуть проблемы при использовании этого метода, когда на другом сервере настроен грейлистинг. Сервер с грейлистингом может сообщить о временной ошибке, так что сервер со встречной проверкой не сможет проверить существование адреса отправителя.
  4. Грейлистинг или серые списки - сервер получателя запоминает триплет с IP-адресом отправителя, адресом отправителя и адресом получателя, а затем сообщает о временной ошибке. Почтовый сервер, соответствующий стандартам, попытается повторить отправку сообщения через некоторое время. Если обе попытки не следуют друг за другом, а происходят спустя некоторый минимальный интервал времени, и если совпал весь триплет, то письмо принимается.

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

    Однако, есть ещё одна сложность - некоторые большие почтовые системы могут каждый раз пытаться отправить письмо с другого IP-адреса. Для обхода подобных ситуаций вместо IP-адреса запоминаются только первых три октета IP-адреса, так что если IP-адрес отправителя находится в той же сети, то письма могут дойти. Более крупные сети обычно добавляются вручную в белый список IP-адресов, почта с которых принимается сразу.

Обычная фильтрация спама происходит уже после приёма письма. Обычно для оценки степени доверия к письму применяются Байесовские фильтры. Они выставляют оценку, основываясь на большом количестве различных признаков, характерных для спама или полезной почты. Например, соответствие заголовков письма SPF-записи в домене отправителя и наличие правильной DKIM-подписи свидетельствует о полезности письма. Их отсутствие, наличие в письме ключевых слов, приёмов оформления HTML-писем, характерных для спама, свидетельствует о том, что письмо бесполезное.

Мой опыт показывает, что обычная фильтрация писем оказывается очень ресурсоёмкой, поэтому я избегаю её использования. Тарпиттинг и встречная проверка отправителя могут вызывать трудно диагностируемые проблемы. Из средств проактивной фильтрации я предпочитаю использовать SPF, чёрные и белые списки совместно грейлистингом. Эти средства предоставляют достаточно хорошую защиту от спама и используют минимум ресурсов, а возникающие с ними проблемы легко поддаются диагностике.

Лучшим из найденных мной в дистрибутиве Debian демонов для грейлистинга оказался демон milter-greylist. Перечислю несколько причин, почему он показался мне лучшим:
  • Написан на C, а стало быть - не требователен к ресурсам.
  • Работает по протоколу Milter, а стало быть почтовую систему можно настроить так, что при его поломке письма будут продолжать приходить.
  • Обладает исключительно гибкими настройками. Например, можно отключить фильтрацию для определённого домена-отправителя, для сети IP-адресов отправителя, для IP-адресов в чёрном списке, для определённого получателя или использовать произвольное сочетание этих критериев, настраивая для каждого из правил время грейлистинга и время действия разрешения.
  • Поддерживает онлайн-синхронизацию данных между несколькими экземплярами демона, работающими на разных компьютерах. Это позволяет использовать общие данные грейлистинга на ферме из SMTP-серверов, занимающихся приёмом почты. Даже если клиент будет каждый раз попадать на разный SMTP-сервер, грейлистинг будет продолжать нормально работать.
  • Не требует для своей работы баз данных SQL.

Устанавливаем пакет с демоном грейлистинга:
# apt-get install milter-greylist
Открываем файл конфигурации /etc/milter-greylist/greylist.conf и заменяем строчки, настраивающие сокет:
socket "/var/spool/postfix/milter-greylist" 666
Процедуру фильтрации грейлистинга будем применять только в одном из двух случаев:
  • IP-адрес отправителя находится чёрном списке zen.spamhaus.org.
  • Письмо адресовано пользователю postmaster, hostmaster, webmaster, abuse или info в нашем домене.
Встречаются администраторы, которые бездумно вписывают все найденные чёрные списки в конфигурацию своего почтового сервера. Я не хочу создавать непробиваемую стену для тех, кто готов работать в соответствии со стандартами и приложить немного дополнительных усилий для отправки почты.

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

Изменим список своих сетей:
list "my network" addr { 127.0.0.1/8 }
Для примера, создадим список IP-адресов своего провайдера. Несмотря на то, что эти IP-адреса могут числиться в списке PBL на spamhaus.org, мы их поместим в белый список:
list "ufanet network" addr { \
        192.168.0.0/16 \
        172.16.0.0/12 \
        10.0.0.0/8 \
        46.191.128.0/17 \
        81.30.176.0/20 \
        81.30.192.0/19 \
        89.189.128.0/19 \
        77.79.128.0/18 \
        79.140.16.0/20 \
        92.50.128.0/18 \
        94.41.0.0/16 \
        95.105.0.0/17 \
        136.169.128.0/17 \
        145.255.0.0/19 \
}
Стоит отметить, что в многострочных правилах после каждой строки, имеющей продолжение, должен стоять символ обратной косой черты.

Заменим получателей, для которых всегда будет применяться грейлистинг:
list "grey users" rcpt { \
        postmaster@domain.tld \
        webmaster@domain.tld \
        hostmaster@domain.tld \
        abuse@domain.tld \
        info@domain.tld \
}
Добавляем правило для чёрного списка zen.spamhaus.org:
dnsrbl "ZEN" zen.spamhaus.org 127.0.0.0/28
И, наконец, сводим все настройки в конечный список контроля доступа (ACL):
racl whitelist list "my network"
racl whitelist list "my friends"
racl whitelist list "broken mta"
racl whitelist list "ufanet network"
racl greylist dnsrbl "ZEN" delay 10m autowhite 3d
racl greylist list "grey users" delay 10m autowhite 3d
racl whitelist default
В файле /etc/default/milter-greylist включаем демон milter-greylist и опять настраиваем сокет:
ENABLED=1
SOCKET="/var/spool/postfix/milter-greylist"
В файле /etc/postfix/main.cf добавляем использование milter-greylist в начало настройки smtpd_milters:
smtpd_milters = unix:/milter-greylist, unix:/clamav-milter, unix:/opendkim/socket
Осталось перезапустить демоны:
# /etc/init.d/milter-greylist start
# /etc/init.d/postfix restart
Фильтрация спама - очень щепетильная тема. Многие администраторы люто негодуют, когда слышат слова "грейлистинг" и "спамхаус". Спорным можно считать и то, что грейлистингу в описанной конфигурации всегда подвергается адрес postmaster, почта которому должна доходить всегда, в том числе для решения проблем с её непрохождением. Я считаю, что показанная здесь конфигурация грейлистинга достаточно либеральна, в том числе потому, что пресловутый спамхаус не используется для безоговорочного отклонения всех писем подряд. Однако, я буду рад услышать ваши доводы.

Примечание от 13 марта 2013 года: Немного поменял порядок проверок в правилах smtpd_*_restrictions.

Продолжение следует...