Продолжаем.
1. Установка и настройка DKIM
DomainKeys Identified Mail (DKIM) — метод E-mail аутентификации, разработанный для обнаружения подделывания сообщений, пересылаемых по email. Метод дает возможность получателю проверить, что письмо действительно было отправлено с заявленного домена. DKIM упрощает борьбу с поддельными адресами отправителей, которые часто используются в фишинговых письмах и в почтовом спаме.
На момент написания статьи в EPEL нет готового пакета OpenDKIM, будем собирать его сами. Собирать буду на рабочем компе под управлением Fedora 31, чтоб не засорять основной сервер. Подготовим среду для сборки, делаем это на рабочем компе и от имени пользователя!!!
1 2 3 4 5 6 |
sudo dnf install mock rpmdevtools rpm-build sudo usermod -a -G mock $(whoami) # Перезагрузка sudo shutdown -r now |
После перезагрузки, скачиваем opendkim-2.*.src.rpm. Качать будем отсюда, заходим и в поиске пишем opendkim. Вот мой результат.
1 2 3 4 5 6 7 8 |
mkdir ~/tmp cd ~/tmp wget https://kojipkgs.fedoraproject.org//packages/opendkim/2.11.0/0.9.fc31/src/opendkim-2.11.0-0.9.fc31.src.rpm # пробуем собрать mock -r epel-8-x86_64 --rebuild opendkim-2.11.0-0.9.fc31.src.rpm |
К сожалению, сборка окончится не удачно, будет ошибка:
1 2 3 4 5 |
..... No matching package to install: 'opendbx-devel' ..... |
Это означает, что в chroot нет хватает пакета ‘opendbx-devel’. Попробуем его добавить в chroot. Для этого скачаем пакет и так же попробуем собрать его. Идем на сайт, ищем наш пакет (opendbx) и ставим.
1 2 3 4 |
wget https://kojipkgs.fedoraproject.org//packages/opendbx/1.4.6/21.fc31/src/opendbx-1.4.6-21.fc31.src.rpm mock -r epel-8-x86_64 --install opendbx-1.4.6-21.el8.x86_64.rpm |
На этот раз, все прошло хорошо, пакет собрался. Теперь его надо установить в chroot, для этого выполняем:
1 2 3 4 5 |
# Устанавливаем на локальном компьютере в chroot mock -r epel-8-x86_64 --install /var/lib/mock/epel-8-x86_64/result/opendbx-1.4.6-21.el8.x86_64.rpm mock -r epel-8-x86_64 --install /var/lib/mock/epel-8-x86_64/result/opendbx-devel-1.4.6-21.el8.x86_64.rpm |
Теперь попробуем собрать opendkim еще раз, но на этот раз надо добавить параметр —no-clean :
1 2 3 |
mock -r epel-8-x86_64 --rebuild --no-clean opendkim-2.11.0-0.9.fc31.src.rpm |
На этот раз сборка прошла без проблем:
1 2 3 4 5 6 7 8 |
..... Finish: rpmbuild opendkim-2.11.0-0.9.fc31.src.rpm Finish: build phase for opendkim-2.11.0-0.9.fc31.src.rpm INFO: Done(opendkim-2.11.0-0.9.fc31.src.rpm) Config(epel-8-x86_64) 0 minutes 38 seconds INFO: Results and/or logs in: /var/lib/mock/epel-8-x86_64/result Finish: run |
По этому пути (/var/lib/mock/epel-8-x86_64/result/) будут лежать готовые пакеты. Необходимо скопировать их на наш сервер и установить:
1 2 3 4 |
# Выполняем на сервере mail dnf install opendbx-1.4.6-21.el8.x86_64.rpm libopendkim-2.11.0-0.9.el8.x86_64.rpm opendkim-2.11.0-0.9.el8.x86_64.rpm -y |
Настроим DKIM:
Немного теории: В основе DKIM лежит ассиметричный алгоритм шифрования. Сообщения подписываются закрытым ключом, который хранится на сервере, а открытый публикуется в TXT-записи в DNS. Для извлечения открытого ключа из публичной записи необходимо «собрать» доменное имя. Оно состоит из нашего домена, обязательной части технологии DKIM — _domainkey, и имени селектора. Т,е. в нашем случае, получится:
selector._domainkey.samara-it.ru
Начнем с генерации ключей. Для этого надо запустить утилиту opendkim-genkey.
1 2 3 |
opendkim-genkey -D /etc/opendkim --domain=$(postconf -h mydomain) --selector=mail |
где:
—domain — имя домена (samara-it.ru)
—selector — имя селектора (mail)
В результате, получим 2 файла: mail.private — приватный ключ и mail.txt — пример записи в DNS с публичным ключом. Установим необходимые права на файлы:
1 2 3 4 5 |
chown opendkim:opendkim /etc/opendkim/mail.private chown opendkim:opendkim /etc/opendkim/mail.txt chmod 600 /etc/opendkim/mail.private |
Теперь надо добавить запись TXT в DNS. Описывать это не буду, у каждого провайдера своя консоль управления. Для проверки воспользуемся этим:
1 2 3 4 5 6 |
dig -t TXT mail._domainkey.samara-it.ru +short # Должны получить примерно такое (вывод обрезан) "v=DKIM1; k=rsa; p=MIGfMA0GCSqG.....TpwIDAQAB" |
Важно понимать, что вывод должен совпадать с файлом /etc/opendkim/mail.txt.
Настройки OpenDKIM находятся в файле /etc/opendkim.conf. Сделаем бэкап этого файла, создадим пустой файл
1 2 3 4 |
mv /etc/opendkim.conf /etc/opendkim.conf.copy nano /etc/opendkim.conf |
и вставим в него следующие:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
# Всегда добавлять заголовок Authentication-Results AlwaysAddARHeader Yes # Не перезапускаться при ошибках AutoRestart No # Подписывать сообщения из поддоменов SubDomains Yes # Удалить все результаты проверки подлинности: заголовки на всех поступающих письмах. # RemoveARAll Yes # Удалить старые подписи в сообщениях, если таковые имеются, при создании подписи RemoveOldSignatures Yes # Указывает, должен ли фильтр генерировать отчетное письмо отправителям, если проверка не пройдена и указан адрес для этой цели. SendReports Yes Canonicalization relaxed/relaxed # Режим работы: подпись и проверка Mode sv UserID opendkim:opendkim # Запись сообщений в syslog Syslog Yes SyslogSuccess Yes LogWhy Yes # задает соответствие селектор - домен - закрытый ключ KeyTable /etc/opendkim/KeyTable # Соответствия отправителей и селектора SigningTable refile:/etc/opendkim/SigningTable ExternalIgnoreList refile:/etc/opendkim/TrustedHosts InternalHosts refile:/etc/opendkim/TrustedHosts PidFile /var/run/opendkim/opendkim.pid Socket inet:10010@localhost ReportAddress "DKIM Error Postmaster" <admin@samara-it.ru> |
Теперь добавим строку в файл /etc/opendkim/KeyTable, в котором задается соответствие селектор — домен — закрытый ключ.
1 2 3 |
mail._domainkey.samara-it.ru samara-it.ru:mail:/etc/opendkim/mail.private |
Далее, необходимо внести изменения в файл /etc/opendkim/SigningTable, в котором задается соответствия отправителей и селектора, добавим строку:
1 2 3 |
*@samara-it.ru mail._domainkey.samara-it.ru |
Правим файл /etc/opendkim/TrustedHosts. Он определяет список внутренних (InternalHosts) и внешних (ExternalIgnoreList) хостов, с которых всю почту надо подписывать, а не проверять. Приводим этот файл к такому виду:
1 2 3 4 5 |
127.0.0.1 *.samara-it.ru 192.168.33.91 |
Теперь необходимо указать postfix, что надо отдавать письма на подпись. Для этого добавим строки в конфиг /etc/postfix/main.cf
1 2 3 4 5 6 |
# Подключаем OpenDKIM milter_default_action = accept smtpd_milters = inet:localhost:10010 non_smtpd_milters = inet:localhost:10010 |
Пробуем запустить OpenDKIM. Запускаем службу и перезапускаем postfix
1 2 3 4 5 |
systemctl start opendkim.service systemctl enable opendkim.service systemctl restart postfix.service |
Для проверки, напишем и отправим письмо, проверим логи и заголовки письма. Напомню, что логи находятся в файле /var/log/maillog
1 2 3 4 5 6 7 8 |
Jan 15 10:18:03 mail postfix/submission/smtpd[17690]: Anonymous TLS connection established from unknown[XX.XX.XX.XX]: TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits) Jan 15 10:18:03 mail postfix/submission/smtpd[17690]: 60ABF8014A: client=unknown[XX.XX.XX.XX], sasl_method=CRAM-MD5, sasl_username=admin@samara-it.ru Jan 15 10:18:03 mail postfix/cleanup[17696]: 60ABF8014A: message-id=<cf8d8591-b713-90a6-23dd-279f1cf6da4a@samara-it.ru> Jan 15 10:18:03 mail opendkim[17038]: 60ABF8014A: DKIM-Signature field added (s=mail, d=samara-it.ru) Jan 15 10:18:03 mail postfix/qmgr[17657]: 60ABF8014A: from=<admin@samara-it.ru>, size=762, nrcpt=1 (queue active) Jan 15 10:18:03 mail postfix/submission/smtpd[17690]: disconnect from unknown[XX.XX.XX.XX] ehlo=2 starttls=1 auth=1 mail=1 rcpt=1 data=1 quit=1 commands=8 |
Обратите внимание на строку: DKIM—Signature field added, это значит, что письмо подписано. Проверяем заголовки в пришедшем письме:
1 2 3 4 5 6 7 8 9 |
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=samara-it.ru; s=mail; t=1579069908; bh=Ha9RIjW21dkEz48QNSNbkzai3WY/3bIUyZLYH7YHvrQ=; h=To:From:Subject:Date; b=qGiC2vmOx9Zf1gxIbYgsixHjOl5VRabb1j+bb5IeUzoPkuO4yJUqzkT/IhlEmNZRj H2RHEEPR9CLlaJVrFtPODvmOKx/zqTvN1JLYAWnMLeQ1ACMZLQtOsIcFm/eEtPlSEn TM7OQgvx+pzWc6BlYrfQBY7nT1kwWS1oouVPPJQc= |
С отправкой все отлично. Проверяем как сервер проверяет входящие письма. Для этого напишем себе письмо, например с ящика gmail и смотрим логи в файле /var/log/maillog
1 2 3 4 5 6 7 8 9 10 11 12 |
Jan 15 10:40:37 mail postfix/smtpd[17864]: AF24B80171: client=mail-lf1-f45.google.com[209.85.167.45] Jan 15 10:40:37 mail postfix/cleanup[17869]: AF24B80171: message-id=<CABuMmsR=u3M_Tp5oKA1D7+Wk3ceb6=TVGvN-srNKbtspdBtUPQ@mail.gmail.com> Jan 15 10:40:37 mail opendkim[17038]: AF24B80171: mail-lf1-f45.google.com [209.85.167.45] not internal Jan 15 10:40:37 mail opendkim[17038]: AF24B80171: not authenticated Jan 15 10:40:37 mail opendkim[17038]: AF24B80171: DKIM verification successful Jan 15 10:40:37 mail postfix/qmgr[17657]: AF24B80171: from=<xxxxxxxxxxx@gmail.com>, size=2657, nrcpt=1 (queue active) Jan 15 10:40:37 mail postfix/smtpd[17864]: disconnect from mail-lf1-f45.google.com[209.85.167.45] ehlo=2 starttls=1 mail=1 rcpt=1 data=1 quit=1 commands=7 Jan 15 10:40:37 mail dovecot[17871]: lda(admin@samara-it.ru): msgid=<CABuMmsR=u3M_Tp5oKA1D7+Wk3ceb6=TVGvN-srNKbtspdBtUPQ@mail.gmail.com>: saved mail to INBOX Jan 15 10:40:37 mail postfix/pipe[17870]: AF24B80171: to=<admin@samara-it.ru>, relay=dovecot, delay=0.2, delays=0.15/0.02/0/0.03, dsn=2.0.0, status=sent (delivered via dovecot service) Jan 15 10:40:37 mail postfix/qmgr[17657]: AF24B80171: removed |
Обращаем внимание на строку DKIM verification successful.
На этом считаем, что настройка OpenDKIM закончена.
2. Настройка SPF
Sender Policy Framework (SPF) — расширение для протокола отправки электронной почты через SMTP. SPF-запись защищает от подделки домен и позволяет предотвратить попадание в спам писем, отправленных с ваших адресов. SPF настраивается для адреса, используемого в envelope-from (SMTP конверте). По сути, это просто запись в DNS.
Создадим TXT запись в DNS следующего вида:
1 2 3 |
v=spf1 +a +mx ~all |
Что будет означать что:
+a +mx — использовать адреса сервера из DNS записей A или MX соответственно
~all — если проверка не прошла, то действовать на усмотрение сервера получателя
Для проверки правильности добавление записи в DNS используем запрос:
1 2 3 4 5 6 |
dig -t TXT samara-it.ru +short # Должны получить ответ: "v=spf1 +a +mx ~all" |
Теперь научим наш postfix проверять входящие письма на предмет корректности записи SPF от других серверов. Для этого надо установить pypolicyd-spf. На момент написания статьи его нет в EPEL, по этому действуем способом, как описано выше. После установки, настраиваем. Для этого надо добавить следующие строки в конец файла /etc/postfix/master.cf
1 2 |
policyd-spf unix - n n - 0 spawn user=nobody argv=/usr/libexec/postfix/policyd-spf |
Обратите внимание, на путь до файла /usr/libexec/postfix/policyd-spf, в документации (man policyd-spf) указан другой. В файл /etc/postfix/main.cf добавим следующие строки:
1 2 3 4 5 6 7 8 |
smtpd_recipient_restrictions = ....... reject_unauth_destination, check_policy_service unix:private/policyd-spf, ....... policyd-spf_time_limit = 3600 |
Настройки проверки SPF записи определяются в файле /etc/python-policyd-spf/policyd-spf.conf. Приведем его к такому виду:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
# Определяет уровень логирования # Может иметь значение от 0 до 5 debugLevel = 1 # для тестирования # Если выставить значение в 0, логирование продолжится, # но к почте не будут применяться никакие действия. TestOnly = 1 # определяет политику проверки поля HELO/EHLO # По умолчанию отбрасываются письма HELO_reject = Fail # определяет политику проверки поля MAIL FROM # По умолчанию отбрасываются письма со статусом Fail Mail_From_reject = Fail # определяют, что делать с сообщениями со статусом # PermError и TempError # По умолчанию сообщения пропускаются в обоих случаях PermError_reject = False TempError_Defer = False # указываются адреса локальных сетевых интерфейсов, # для которых нужно пропустить проверку skip_addresses = 127.0.0.0/8,192.168.33.91/32 |
Более подробно о всех параметрах можно узнать тут:
1 2 3 |
man policyd-spf.conf |
Обратите внимание на параметры: Reject_Not_Pass_Domains, Whitelist.
Перезапустим Postfix
1 2 3 |
systemctl restart postfix.service |
Проверяем логи.
1 2 3 |
policyd-spf[31985]: prepend Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=XX.XX.XX.XX; helo=mail-XXXXXXXX.google.com; envelope-from=XXXXXXXXXXX@gmail.com; receiver=<UNKNOWN> |
Все отлично!
3. Настроим DMARC
Domain-based Message Authentication, Reporting and Conformance (DMARC) — это техническая спецификация, созданная группой организаций для борьбы со спамерами, подделывающими адреса отправителей. Она основана на идентификации почтовых доменов отправителя на основании правил и признаков, заданных на почтовом сервере получателя.
Для того, чтобы Postfix мог проводить DMARC проверки для входящей почты, нужно установить пакет OpenDMARC. На момент написания статьи в EPEL нет готового пакета OpenDMARC, будем собирать его сами по технологии, описанного в п.1. После сборки пакета, установим его на сервер и начнем настраивать. Для этого сделаем бэкап файла настроек и создадим пустой файл
1 2 3 4 |
mv /etc/opendmarc.conf /etc/opendmarc.conf.copy nano /etc/opendmarc.conf |
и вставим в него следующие:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
# Обычно в качестве идентификатора указывается полное доменное имя сервера, на котором производится проверка AuthservID mail.samara-it.ru # автоматический перезапуск сервиса в случае падения AutoRestart yes # допустимая частота падений сервиса. В данном случае не более 10 раз за 1 час AutoRestartRate 10/1h # включение рассылки отчетов о неудачных проверках FailureReports yes # адрес, от имени которого будет происходить рассылка отчетов FailureReportsSentBy noreply-dmarc@samara-it.ru # расположение файла, в который записывается информация, используемая для создания сводных отчетов. HistoryFile /var/run/opendmarc/opendmarc.dat # расположение файла, содержащего список имен хостов, IP адресов и CIDR выражений, которые нужно исключить из проверки IgnoreHosts /etc/opendkim/TrustedHosts # исключение из проверки аутентифицированных клиентов IgnoreAuthenticatedClients yes # действие в случае неудачной проверки # yes — отклонить письмо # no — пропустить письмо и добавить в заголовок сообщения поле с результатами проверки RejectFailures no Syslog yes UMask 002 # Socket для подключения к OpenDMARC Socket inet:10020@localhost |
Более подробно о всех параметрах можно узнать тут:
1 2 3 |
man opendmarc.conf |
Теперь необходимо указать postfix, что письма надо проверять на соответствия. Для этого исправим строки в конфиге /etc/postfix/main.cf. Здесь важна последовательность. В начале указывается Socket для подключения к OpenDKIM, затем к OpenDMARC.
1 2 3 4 |
# Подключаем OpenDKIM и OpenDMARK smtpd_milters = inet:localhost:10010 inet:localhost:10020 |
Добавим прав на файл, запустим службу OpenDMARC и добавляем ее в автозапуск, и перезапускаем postfix.
1 2 3 4 5 6 7 |
# Добавим прав на чтение файла для opendmarc chmod 644 /etc/opendkim/TrustedHosts systemctl enable --now opendmarc.service systemctl restart postfix.service |
Отправляем себе письмо с другого почтового сервера (к примеру gmail) и проверяем логи:
1 2 3 4 5 6 7 8 9 |
policyd-spf[3761]: prepend Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=XX.XX.XX.XX; helo=mail-xxxxxx.google.com; envelope-from=xxxxxxxxx@gmail.com; receiver=<UNKNOWN> postfix/smtpd[3753]: 74B1A80155: client=mail-xxxxxx.google.com[XX.XX.XX.XX] postfix/cleanup[3762]: 74B1A80155: message-id=<CABuMmsS6+uEo88wt7KxOUVFAPaTzJXx6w3j4XN1cjPLbJxZKnA@mail.gmail.com> opendkim[1020]: 74B1A80155: mail-xxxxxx.google.com [XX.XX.XX.XX] not internal opendkim[1020]: 74B1A80155: not authenticated opendkim[1020]: 74B1A80155: DKIM verification successful opendmarc[3621]: 74B1A80155: gmail.com pass |
Как видим, все проверки пройдены. Теперь настроим запись в DNS, чтоб принимающие сервера знали о нашем DMARC, добавим запись TXT следующего содержания:
1 2 3 |
_dmarc.samara-it.ru. 3600 IN TXT "v=DMARC1; p=none; rua=mailto:postmaster@samara-it.ru" |
Описание значений можно найти тут