DomainKeys Identified Mail (DKIM) — технология, направленная на борьбу с поддельными почтовыми сообщениями. Для почтового домена генерируется пара ключей, открытый и закрытый. Закрытым ключом подписываются исходящие сообщения. Открытый ключ добавляется на DNS сервер в виде TXT записи. Когда принимающий сервер находит в заголовке сообщения DKIM подпись, он выполняет DNS запрос для получения открытого ключа. С помощью открытого ключа сервер определяет валидность DKIM подписи и решает, что делать с письмом. В зависимости от результатов и политики проверки, письмо может быть принято, отброшено, либо отправлено в спам. Информация с результатами проверки добавляется в заголовок сообщения и в дальнейшем может быть использована анти спам фильтрами. Основное отличие DKIM проверки от описанной ранее SPF проверки заключается в том, что SPF работает с информацией, полученной из полей конверта сообщения, а DKIM с информацией, полученной из заголовка сообщения.
Все что перечислено до команды DATA, это поля конверта сообщения, с ними работает SPF. Все что находится после команды DATA, является заголовком сообщения, с этой информацией работает DKIM.
Для практической демонстрации будут использованы внутренние DNS с IP адресами 192.168.1.21 и 192.168.1.22. На них созданы зоны 4skill.loc и 4skill.ru. Зону 4skill.loc будет обслуживать SMTP сервер mail.4skill.loc с IP адресом 192.168.1.35. Зону 4skill.ru будет обслуживать SMTP сервер mail.4skill.ru с IP адресом 192.168.1.36.
В качестве ОС для SMTP серверов будет использоваться Ubuntu Server 16.04. После установки Ubuntu Server 16.04, изменим имя сервера на mail
# hostnamectl set-hostname mail
Укажем полное и сокращенное имя сервера в файле hosts
# nano /etc/hosts 127.0.0.1 localhost 127.0.1.1 mail.4skill.loc mail . . .
Определим сетевые настройки
# nano /etc/network/interfaces . . . # The primary network interface auto ens32 iface ens32 inet static address 192.168.1.35 netmask 255.255.255.0 gateway 192.168.1.1 dns-nameservers 192.168.1.21 192.168.1.22 dns-search 4skill.loc
Более подробно о настройке сети написано в статье Ubuntu Server настройка сети.
Для применения настроек выполним перезагрузку
# reboot
Обновим индексы пакетов
# apt update
Обновим систему
# apt upgrade
Более подробно об обновлении написано в статье Обновление Ubuntu Server.
Установим Postfix
# apt install postfix
Тип настройки почтового сервера оставляем без изменений и нажимаем «Ok».
В поле системное почтовое имя указываем обслуживаемый домен 4skill.loc.
Полная установка Postfix в связке с Dovecot описана в статье Postfix Dovecot LDAP.
По умолчанию Postfix не умеет подписывать и проверять сообщения с использованием технологии DKIM. Для обеспечения данной возможности, установим пакеты OpenDKIM и OpenDKIM-Tools. OpenDKIM-Tools используется для генерации ключей
# apt install opendkim opendkim-tools
Приведем конфигурационный файл OpenDKIM к следующему виду
# nano /etc/opendkim.conf AutoRestart yes AutoRestartRate 10/1h Canonicalization relaxed/relaxed ExternalIgnoreList refile:/etc/opendkim/trusted_hosts InternalHosts refile:/etc/opendkim/trusted_hosts KeyTable refile:/etc/opendkim/key_table SigningTable refile:/etc/opendkim/signing_table ExemptDomains refile:/etc/opendkim/no_check_domains PeerList refile:/etc/opendkim/no_check_hosts On-BadSignature accept ReportAddress dkim.report@4skill.loc SendReports yes RequestReports yes SignHeaders From,To,Subject,Date,Message-ID Syslog yes SyslogSuccess yes #LogWhy yes UMask 002 Nameservers 192.168.1.21,192.168.1.22
- AutoRestart — автоматический перезапуск сервиса в случае падения.
- AutoRestartRate — допустимая частота падений сервиса. В данном случае не более 10 раз за 1 час.
- Canonicalization — канонизация для заголовка/тела сообщения. Подробнее об это тут.
- ExternalIgnoreList — список внешних хостов, которые могут производить пересылку почты от имени подписываемого домена без аутентификации.
- InternalHosts — список внутренних хостов, чья исходящая почта не должна проверяться, но должна быть подписана.
- KeyTable — список ключей, используемых для подписи.
- SigningTable — список доменов, сопряженных с ключами из KeyTable.
- ExemptDomains — список доменов, для которых не будет производиться проверка.
- PeerList — список хостов, для которых не будет производиться проверка.
- On-BadSignature — что делать с письмом в случае неудачной проверки. Возможны варианты:
∘ accept — пропустить(по умолчанию);
∘ discard — отбросить сообщение без уведомления;
∘ quarantine — поместить сообщение в спам;
∘ reject — отбросить сообщение;
∘ tempfail — выдать сообщение об ошибке. - ReportAddress — адрес, от имени которого будет происходить рассылка отчетов о неудачных проверках.
- SendReports — включение рассылки отчетов о неудачных проверках.
- RequestReports — включение в подпись тега r=y. Данный тег активирует запрос на получение отчетов о неудачных проверках.
- SignHeaders — набор полей заголовка сообщения, которые будут включены в создаваемую подпись.
- Syslog — запись логов в syslog.
- SyslogSuccess — включение в лог информации об успешных подписях и проверках.
- LogWhy — включение более детального логирования.
- UMask — маска прав для Socet файла.
- Nameservers — список используемыех DNS.
Подробное описание всех параметров можно найти на странице opendkim.conf.
Параметр Nameservers не обязательно указывать. В данном примере он используются в демонстрационных целях, связанных с использованием локальных DNS. Дело в том, что любой запрос на получение открытого ключа от локальных DNS завершится ошибкой, сигнализирующей об отсутствии записи, содержащей открытый ключ
# opendkim-testkey -d 4skill.loc -s mail opendkim-testkey: 'mail._domainkey.4skill.loc' record not found
Это связано с тем, что OpenDKIM использует свой собственный список DNS, зашитый в код программы, а не тот, который указан в параметре dns-nameservers. Так как используемые OpenDKIM DNS являются внешними, они ничего не знают о записях, хранящихся на внутренних DNS. Чтобы заставить OpenDKIM использовать внутренние DNS, был определен параметр Nameservers, со списком локальных DNS.
Создадим каталог для хранения ключей
# mkdir -p /etc/opendkim/keys/4skill.loc
Добавим ключи для домена 4skill.loc
# opendkim-genkey -D /etc/opendkim/keys/4skill.loc -d 4skill.loc -s mail
Ключ -D определяет каталог для записи ключей. Ключ -d указывает название домена. Ключ -s указывает название селектора. Селектор может быть произвольным. Обычно селектор отражает название сервиса, дату создания ключа, или битность ключа. В данном случае это название сервиса.
Пользователь, от имени которого работает сервис OpenDKIM, должен иметь доступ к закрытому ключу
# chown opendkim /etc/opendkim/keys/4skill.loc/*.private
Открытый ключ находится в файле с расширением .txt
# cat /etc/opendkim/keys/4skill.loc/*.txt mail._domainkey IN TXT ( "v=DKIM1; k=rsa; " "p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDMtyLiYLXF0ywByDzfnQmdI+OMBsr6dg0OfXnejQtKwwCKmxLdxdk7dXXca7ZaO10b35deSX2XQuCuKp0ZeVsRAQsEu4dAYrJ/5Km7Rh3V45uLv1w7ksky128u6oiqllL5iVg+MWWQYtbedO7hT/Rod+aXb7DV3NjNAIl53ZdPtQIDAQAB" ) ; ----- DKIM key mail for 4skill.loc
Добавим его в локальные DNS. Откроем оснастку «Диспетчер DNS», нажмем правой кнопкой мыши по DNS зоне, выберем «Другие новые записи…» в окне «Тип записи ресурса» выберем «Текст (TXT)» и нажмем «Создать запись…»
Укажем данные открытого ключа
Выполним проверку
# opendkim-testkey -d 4skill.loc -s mail -vvv opendkim-testkey: using default configfile /etc/opendkim.conf opendkim-testkey: checking key 'mail._domainkey.4skill.loc' opendkim-testkey: key not secure opendkim-testkey: key OK
Создадим файл, определяющий от кого подписывать почту
# nano /etc/opendkim/trusted_hosts ::1 127.0.0.1 192.168.1.10
В данном примере будет подписываться почта, сформированная на самом почтовом сервере, и пересылаемая от узла 192.168.1.10. Даже если явно не указывать ::1 или 127.0.0.1, почта сформированная почтовыми клиентами пользователей, прошедших аутентификацию на сервере будет подписана. Явное указание адреса петлевого интерфейса дает возможность подписания почты, сформированной утилитой telnet на почтовом сервере(# telnet localhost 25).
Создадим файл, определяющий список закрытых ключей
# nano /etc/opendkim/key_table 4skill.loc %:mail:/etc/opendkim/keys/%/mail.private
В данном примере используется переменная «%». Она заменяется названием домена отправителя при создании подписи. Использование переменной возможно из-за добавления префикса refile: в начале пути к фалу key_table в opendkim.conf. Та же запись без использование префикса имеет вид
4skill.loc 4skill.loc:mail:/etc/opendkim/keys/4skill.loc/mail.private
Каждый ключ прописывается отдельной строкой и имеет формат
<название ключа> <название домена>:<название селектора>:<путь к закрытому ключу>
Создадим файл, сопоставляющий закрытый ключ с именем домена
# nano /etc/opendkim/signing_table *@4skill.loc %
Без переменной запись выглядела бы так
*@4skill.loc 4skill.loc
Формат записи следующий
<название домена> <название ключа из key_table>
Создадим файлы, определяющий список хостов и доменов, для которых не нужно производить проверку
# touch /etc/opendkim/no_check_hosts # touch /etc/opendkim/no_check_domains
Формат заполнения данных файлов такой же как у trusted_hosts.
Укажем SOCKET для подключения к OpenDKIM
# nano /etc/default/opendkim
заменим строку
SOCKET="local:/var/run/opendkim/opendkim.sock"
на
SOCKET="local:/var/spool/postfix/var/run/opendkim/opendkim.sock"
Создадим каталог для SOCKETa
# mkdir -p /var/spool/postfix/var/run/opendkim/
Выставим права на созданный каталог
# chown opendkim:opendkim /var/spool/postfix/var/run/opendkim/
Чтобы Postfix мог подключаться к SOCKETу OpenDKIM, добавим пользователя postfix в группу opendkim
# gpasswd -a postfix opendkim
Укажем Postfix как подключаться к OpenDKIM. Для этого добавим к конец main.cf следующие строки
# nano /etc/postfix/main.cf . . . smtpd_milters = unix:/var/run/opendkim/opendkim.sock non_smtpd_milters = $smtpd_milters
Для взаимодействия Postfix и OpenDKIM через сеть, нужно в /etc/default/opendkim закоментировать все строки и раскоментировать
SOCKET="inet:12345@localhost"
А в /etc/postfix/main.cf добавить
smtpd_milters = inet:localhost:12345 non_smtpd_milters = $smtpd_milters
Перезапустим OpenDKIM
# service opendkim restart
Перезапустим Postfix
# service postfix restart
Настройка сервера mail.4skill.ru производится по аналогии с mail.4skill.loc.
Зайдем на mail.4skil.loc и отправим сообщение используя telnet
# telnet localhost 25 Trying ::1... Connected to localhost. Escape character is '^]'. 220 mail.4skill.loc ESMTP Postfix (Ubuntu) helo mail.4skill.loc 250 mail.4skill.loc mail from: root@4skill.loc 250 2.1.0 Ok rcpt to: root@4skill.ru 250 2.1.5 Ok data 354 End data with . From: root@4skill.loc . 250 2.0.0 Ok: queued as 4E0B92035D quit 221 2.0.0 Bye Connection closed by foreign host.
На основании домена, извлекаемого из поля From, происходит подпись письма. Если поле From отсутствует, письмо не будет подписано.
Посмотрим на содержание отправленного письма на сервере mail.4skill.ru
# tail -n24 /var/mail/root From root@4skill.loc Tue Oct 24 12:33:51 2017 Return-Path: <root@4skill.loc> X-Original-To: root@4skill.ru Delivered-To: root@4skill.ru Received: from mail.4skill.loc (mail.4skill.loc [192.168.1.35]) by mail.4skill.ru (Postfix) with ESMTP id 867D521B32 for <root@4skill.ru>; Tue, 24 Oct 2017 12:33:51 +0300 (MSK) Authentication-Results: mail.4skill.ru; dkim=pass (1024-bit key; unprotected) header.d=4skill.loc header.i=@4skill.loc header.b=d2ji+6+Q; dkim-atps=neutral Received: from mail.4skill.loc (localhost [IPv6:::1]) by mail.4skill.loc (Postfix) with SMTP id 4E0B92035D for <root@4skill.ru>; Tue, 24 Oct 2017 12:33:31 +0300 (MSK) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=4skill.loc; s=mail; t=1508837631; r=y; bh=47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=; h=From:Message-Id:Date; b=d2ji+6+QGIKcGj1MN3AeNecbuPW2Fw7SWnnMvyhBhYuhYAhwcdTgjqD5VD1TddFjG RTkbfwc+jnQ7V0A2+63pr2l6p/NmNpB+wdEp45qu5GStma51XljBtQjT0lrmmTUuD4 OnN+iw0eEhSSWuFKrAKc5YkUauZUZUmVfTHoBAmc= From: root@4skill.loc Message-Id: <20171024093338.4E0B92035D@mail.4skill.loc> Date: Tue, 24 Oct 2017 12:33:31 +0300 (MSK)
Строка Authentication-Results является результатом проверки. Она добавляется к заголовку письма принимающим сервером. В данном случае письмо успешно прошло проверку, об этом свидетельствует статус dkim=pass. Строка DKIM-Signature являются началом DKIM подписи. Она была сформирована сервером источником. Данная DKIM подпись содержит в себе тег r=y. Он добавляется в подпись, если в opendkim.conf параметр RequestReports имеет значение yes. Это означает, что сервер отправитель запрашивает отчет, в случае неудачной проверки. Отчет направляется на адрес, указанный в TXT записи
_report._domainkey.<название домена>
Добавим данную запись для домена 4skill.loc
Первый тег ra=dkim.report содержит в себе адрес, на который нужно отсылать отчеты о неудачных проверках. В данном теге нужно указывать только первую часть адреса до символа @. Доменная часть добавляется автоматически. Второй тег не является обязательным и может иметь значение от 0 до 100 включительно. Он указывает какой процент отчетов должен быть отправлен. По умолчанию используется значение 100.
а что означет dkim-atps=neutral при dkim=pass
ATPS (Authorized Third Party Signer) это экспериментальная спецификация, позволяющая осуществлять подпись почтовых сообщений третей стороной.
К примеру исходящие письма от домена dom1, подписываются ключом домена dom2.
dkim-atps=neutral(no key for signature) означает, что письмо не имеет подписи третей стороны.
Подробно о принципе работы ATPS написано в RFC 6541.
Единственное что я не понимаю это нужда изменения настроек сокета, зачем мы меняли настройки
SOCKET=»local:/var/spool/postfix/var/run/opendkim/opendkim.sock»
smtpd_milters = unix:/var/run/opendkim/opendkim.sock
non_smtpd_milters = $smtpd_milters
а потом тут же перепрыгнули на 12345?
Спасибо.
Определенные службы Postfix запускаются в «chroot» окружении. Иными словами, запущенная в «chroot» окружении служба, будет разрешать имена файлов относительно каталога очереди Postfix(/var/spool/postfix).
Включение/отключение «chroot» окружения определяется в файле /etc/postfix/master.cf.
В статье описано 2 варианта подключения OpenDKIM к Postfix.
Первый, через SOCKET. Второй, по сети. 12345 — это вариант по сети.