Только начинаете с DMARC? Начните с основ →
Почти каждая ротация DKIM, после которой ломается почта, спотыкается не о криптографию, а о DNS. Новый ключ записали под старый селектор, хотя резолверы ещё держали старый в кэше. Запись длиной 410 символов не влезла в DNS-панель. Подписывание включили раньше, чем запись начала резолвиться. Или забыли про селектор какого-нибудь поставщика, который всё ещё на 1024 битах.
Для этого селекторы и придуманы: RFC 6376 прямо называет их способом регулярно заменять публичные ключи без перерывов в работе. Ниже — порядок действий для ключей, которые вы держите сами, а затем отдельно для Google Workspace, Microsoft 365 и сторонних отправителей. Как селектор связан с именем в DNS, объясняет статья «Что такое DKIM».
Почему 1024 бит уже недостаточно
RFC 8301, раздел 3.2 задаёт нижнюю границу и ориентир: отправитель обязан (MUST) использовать RSA-ключи длиной не менее 1024 бит, а ключи от 2048 бит ему следует (SHOULD) использовать. Ключ на 1024 бита по-прежнему проходит проверку, но это нижняя планка, а не рекомендация.
Там же запрещён SHA-1: rsa-sha1 нельзя применять ни для подписи, ни для проверки. Если сервер до сих пор подписывает 1024-битным ключом, он вполне может оказаться настолько старым, что подписывает ещё и через SHA-1. Раз уж вы им занялись, проверьте тег a= — там должно стоять a=rsa-sha256.
Длину ключа видно прямо по записи. Публичный RSA-ключ на 1024 бита в base64 начинается с MIGfMA0 и занимает 216 символов, ключ на 2048 бит начинается с MIIBIjAN и занимает 392. Проверка DKIM оценит длину ключа для любого селектора, который вы укажете.
Сначала — инвентаризация селекторов
Перечислить селекторы домена через DNS невозможно. Зато сводные отчёты показывают все, которыми реально подписывается почта: по RFC 9990 селектор обязательно указывается в каждом результате DKIM — это значение тега s= из подписи, по которому шла проверка.
Соберите отчёты за 30 дней и составьте по источникам список пар «домен подписи — селектор»:
<dkim>
<domain>example.com</domain>
<selector>mail</selector>
<result>pass</result>
</dkim>
Наверняка источников окажется больше, чем вы помните: маркетинговая платформа, служба поддержки, система выставления счетов, релей для сканера. Каждый источник — отдельная ротация и отдельный ответственный. Как разобрать остальной XML, рассказывает статья о чтении сводных отчётов DMARC.
Ротация ключа на вашем сервере
Этот раздел — про подписывание, которое вы держите у себя: OpenDKIM, rspamd, MTA со встроенным DKIM. Сроки взяты из рекомендаций M3AAWG по ротации ключей DKIM.
День 0: новый ключ под новым селектором
Старое имя селектора для нового ключа не годится. В RFC 6376 сказано прямо: использовать селекторы повторно для новых ключей неразумно, новым ключам нужны новые селекторы. На практике всё упирается в кэш: пока не истечёт TTL, резолверы отдают старый ключ, и письма, подписанные новым, проверку не проходят.
M3AAWG советует давать селекторам имена, по которым понятны поток почты, дата и длина ключа, — например, sales-201309-1024. Вполне подойдёт s202610. Генерируем пару ключей:
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out s202610.private.pem
openssl pkey -in s202610.private.pem -pubout -outform DER | openssl base64 -A
Ограничение в 255 символов
Строка v=DKIM1; k=rsa; p= с 2048-битным ключом занимает около 410 символов. А одна строка в TXT-записи, согласно RFC 1035, раздел 3.3, может быть длиной до 256 символов, считая октет длины, — то есть 255 символов данных. Поэтому запись публикуется как одна TXT-запись из двух или более строк:
s202610._domainkey.example.com. 3600 IN TXT (
"v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA..."
"...QIDAQAB" )
RFC 6376, раздел 3.6.2.2 требует, чтобы получатель перед использованием соединял строки, не вставляя между ними пробелов. Если ваша DNS-панель не разбивает длинное значение сама, ручной способ описан в руководстве Google по устранению неполадок: разделите ключ на строки, возьмите каждую в кавычки и введите их подряд.
Теперь запросите запись у двух публичных резолверов:
dig +short TXT s202610._domainkey.example.com @1.1.1.1
dig +short TXT s202610._domainkey.example.com @8.8.8.8
После склейки строки в кавычках должны дать ровно тот ключ, который вы сгенерировали: без пробела на стыке, без лишних кавычек, без потерянных символов.
Порядок шагов здесь важен. Если включить подписывание раньше, чем появилась запись, каждый получатель, запросивший селектор, закэширует ответ «такого имени нет». Срок такого кэша по RFC 2308, раздел 5 — меньшее из двух значений: поле MINIMUM в SOA или TTL самой SOA. Всё это время подписи не будут проходить проверку, даже когда запись уже опубликована.
Дни 1–2: переключаем подписывание
Когда оба резолвера начнут отдавать запись, переведите подписывание на новый ключ: в OpenDKIM — строкой в KeyTable, в rspamd — селектором и путём к ключу в dkim_signing.conf. Отправьте письмо на внешний ящик и откройте заголовки. В DKIM-Signature должны быть s=s202610 и a=rsa-sha256, в Authentication-Results — dkim=pass.
Дни 2–30: старый ключ не трогаем
Письма со старой подписью всё ещё в пути. Отложенные письма почтовые очереди пытаются доставить по нескольку дней: Postfix по умолчанию сдаётся только через пять (maximal_queue_lifetime). Кроме того, RFC 6376, раздел 5.2 предупреждает, что проверяющая сторона может проверить подпись позже — вплоть до момента, когда письмо откроет конечный получатель. M3AAWG советует оставлять старый публичный ключ в DNS без изменений от семи до 30 дней.
Затем отзываем старый ключ
Когда этот срок пройдёт, замените старую запись пустым ключом:
mail._domainkey.example.com. 3600 IN TXT "v=DKIM1; p="
По RFC 6376, раздел 3.6.1 пустое значение означает, что публичный ключ отозван. Удалить запись RFC тоже разрешает, но M3AAWG за пустой ключ и пишет прямо: запись селектора не удаляйте. Отозванный селектор показывает получателям, что ключ выведен из эксплуатации намеренно.
Через неделю после переключения в отчётах по этому источнику должен остаться только новый селектор.
M3AAWG рекомендует и заранее держать в DNS следующий публичный ключ: тогда экстренная ротация после утечки сводится к перенастройке сервера подписи, без ожидания DNS. А плановую ротацию внесите в календарь: по M3AAWG ключи стоит менять не реже чем раз в полгода.
Если вести DNS-часть вручную не хочется, управляемый DKIM в DDMARC на тарифе Professional генерирует пару ключей и публикует публичный ключ в своей зоне за одной записью CNAME. Ротация тогда создаёт новый селектор, а вам остаётся заменить этот CNAME. Приватный ключ вы по-прежнему устанавливаете на свой сервер подписи.
Google Workspace
В консоли администратора перейдите в Apps > Google Workspace > Gmail > Authenticate email, нажмите Generate New Record и выберите длину ключа 2048 бит. В руководстве Google по настройке указано: если в домене уже есть ключ DKIM с префиксом google, в этом поле нужно ввести другой префикс. Во время ротации он как раз есть. Возьмите новый префикс, например google2026, — и новая запись появится рядом с google._domainkey, а не заменит её.
Опубликуйте запись и убедитесь, что она резолвится (по данным Google, прежде чем аутентификация DKIM заработает, может пройти до 48 часов). Только после этого нажмите Start authentication. Запись google._domainkey оставьте на тот же период перекрытия и лишь затем отзовите. Настройка первого ключа описана в руководстве для Google Workspace.
Microsoft 365
В Microsoft 365 используются две записи CNAME — selector1._domainkey и selector2._domainkey (см. руководство по настройке). При ротации меняются ключи, на которые они указывают, а в вашем DNS ничего не меняется. При переходе на 2048 бит есть два подвоха. Во-первых, согласно документации Microsoft по DKIM, новый приватный ключ начинает подписывать письма через четыре дня (96 часов). Во-вторых, справка по Rotate-DkimSigningConfig уточняет: -KeySize 2048 обновляет только неактивный селектор, так что после ротации команду нужно выполнить ещё раз, уже для второго:
Rotate-DkimSigningConfig -Identity example.com -KeySize 2048
# after RotateOnDate passes, for the other selector
Rotate-DkimSigningConfig -Identity example.com -KeySize 2048
Get-DkimSigningConfig -Identity example.com | Format-List Selector1KeySize,Selector2KeySize,RotateOnDate,SelectorAfterRotateOnDate
Закладывайте восемь дней. New-DkimSigningConfig по умолчанию до сих пор создаёт 1024-битные ключи, поэтому, прежде чем считать какой-то селектор 2048-битным, посмотрите Selector1KeySize и Selector2KeySize.
Сторонние отправители
По M3AAWG инициатива за вами: запрос на ротацию должен исходить от владельца организационного домена. Дальше всё зависит от того, как устроена подпись.
Делегирование через CNAME. Вы публикуете записи CNAME, указывающие на поставщика, и он может менять ключи за ними, не трогая ваш DNS. В примере M3AAWG таких записей три: одним действующим ключом третья сторона подписывает, пока остальные ротируются. Узнайте у поставщика, как часто он меняет ключи, и проверьте длину ключа, на который указывает CNAME. Запись CNAME, которая кажется лишней, не удаляйте: за ней может быть следующий ключ.
TXT-запись, опубликованная вами. Поставщик однажды прислал вам публичный ключ, и тот так и лежит в вашей зоне — той же длины, что и в день публикации. Именно такие селекторы годами остаются на 1024 битах. Чтобы заменить ключ, запросите у поставщика новую пару ключей под новым селектором и вместе пройдите те же шаги: публикация, переключение, ожидание, отзыв.
Ed25519: дополнение к RSA, а не замена
RFC 8463 требует, чтобы проверяющая сторона поддерживала Ed25519-SHA256, а ключ длиной 44 символа помещается в одну TXT-строку. И всё же раздел того же RFC о переходе предполагает, что отправитель ставит несколько подписей — со старым и с новым алгоритмом, каждую под своим селектором. Microsoft 365 подписывает только RSA-ключами: в справке по командлету прямо указано, что ключи Ed25519 не поддерживаются. Поэтому сначала перейдите на RSA 2048, а подпись Ed25519 добавьте рядом там, где ваш сервер подписи это поддерживает.