Ротация DKIM-ключей: зачем, когда и как
DKIM-подпись защищает каждое ваше письмо от подделки. Но сам ключ, которым вы подписываете, - такой же расходник, как SSL-сертификат. Его нужно менять. Вопрос - как это сделать без потери доставляемости и без паники в пятницу вечером.
Зачем вообще менять DKIM-ключ
Короткий ответ: потому что ключи стареют. Длинный ответ состоит из трёх частей.
Криптографическое старение. Приватный ключ лежит на сервере месяцами или годами. За это время он может утечь при компрометации сервера, попасть в бэкап, который скопировали на флешку, или оказаться в логах деплоя. Чем дольше ключ живёт, тем выше вероятность, что кто-то его получит. А если приватный ключ скомпрометирован, злоумышленник может подписывать письма от имени вашего домена - и DMARC пропустит их как легитимные.
Рекомендации вендоров. Google в документации Postmaster Tools рекомендует ротировать DKIM-ключи минимум раз в год. M3AAWG (Messaging, Malware and Mobile Anti-Abuse Working Group) в своём best practices document советует каждые 6 месяцев. Некоторые крупные ESP - Mailgun, Postmark - ротируют ключи клиентов автоматически каждый квартал.
Переход на более длинные ключи. Если вы до сих пор используете 1024-битный RSA-ключ, ротация - удобный момент обновиться до 2048 бит. Google с 2023 года штрафует за короткие ключи. Кроме того, RFC 8463 добавил поддержку Ed25519 для DKIM - это алгоритм на эллиптических кривых, компактнее и быстрее RSA. Пока его поддерживают не все провайдеры, но тренд очевиден.
Когда пора менять ключ
Есть плановая ротация и экстренная. Плановая - раз в 6-12 месяцев, по расписанию. Экстренная - если произошла утечка или вы подозреваете компрометацию.
Признаки, что ключ нужно менять немедленно:
- Сервер, где хранился приватный ключ, был скомпрометирован.
- Вы обнаружили DKIM-подписанные письма, которые не отправляли.
- Уволился администратор, имевший доступ к ключам, и вы не уверены, что он не сохранил копию.
- Ключ - 1024 бит или менее, и вы видите предупреждения в DMARC-отчётах.
Для плановой ротации выберите день с минимальной нагрузкой на рассылки. Вторник-среда, первая половина дня. Не пятница, не выходные, не день перед распродажей.
Принцип: два селектора, ноль даунтайма
DKIM использует селекторы - произвольные строки, которые указывают принимающему серверу, какой публичный ключ брать из DNS. Селектор записывается в заголовке каждого подписанного письма (тег s=). Принимающий сервер достаёт ключ по адресу selector._domainkey.yourdomain.com.
Ротация строится на этом механизме. Схема:
- Генерируете новую пару ключей с новым селектором.
- Публикуете новый публичный ключ в DNS. Ждёте пропагации.
- Переключаете сервер на подпись новым ключом и новым селектором.
- Старую DNS-запись оставляете на 24-48 часов (письма в очередях ещё подписаны старым ключом).
- Удаляете старую DNS-запись. Уничтожаете старый приватный ключ.
Ключевой момент: старый и новый публичные ключи сосуществуют в DNS одновременно. Принимающий сервер всегда проверяет подпись по тому селектору, который указан в письме. Никакого конфликта, никакого даунтайма.
Шаг 1. Генерация нового ключа
RSA 2048 бит - текущий стандарт. Генерация через openssl:
# Генерация приватного ключа RSA 2048 openssl genrsa -out dkim_s2_private.pem 2048 # Извлечение публичного ключа openssl rsa -in dkim_s2_private.pem -pubout -out dkim_s2_public.pem # Публичный ключ одной строкой (для DNS-записи) grep -v "^-" dkim_s2_public.pem | tr -d '\n'
Имя файла содержит s2 - это имя нового селектора. Если текущий селектор s1, новый будет s2. В следующий раз - s3 или снова s1 (к тому моменту старую запись вы уже удалили). Некоторые команды используют дату: dkim202604. Это удобнее - сразу видно, когда ключ создан.
Если хотите попробовать Ed25519 (RFC 8463):
# Ed25519 - компактный ключ, быстрая подпись openssl genpkey -algorithm Ed25519 -out dkim_ed_private.pem openssl pkey -in dkim_ed_private.pem -pubout -out dkim_ed_public.pem
Ed25519 даёт публичный ключ длиной 44 символа в base64 вместо 392 у RSA-2048. DNS-запись получается компактной, нет проблем с лимитом 255 символов на строку. Но проверяйте совместимость: Yahoo и Gmail поддерживают Ed25519, Mail.ru и некоторые корпоративные серверы на Exchange - пока нет. Безопасный подход - публиковать два ключа: RSA как основной, Ed25519 как дополнительный.
Шаг 2. Публикация в DNS
Добавьте TXT-запись для нового селектора. Старую пока не трогайте.
; Старый ключ (пока оставляем) s1._domainkey.yourdomain.com. IN TXT "v=DKIM1; k=rsa; p=MIIBIjAN...старый_ключ..." ; Новый ключ s2._domainkey.yourdomain.com. IN TXT "v=DKIM1; k=rsa; p=MIIBIjAN...новый_ключ..."
Проверка пропагации:
# Убедиться, что новая запись доступна dig TXT s2._domainkey.yourdomain.com +short # Убедиться, что старая ещё на месте dig TXT s1._domainkey.yourdomain.com +short
Если используете Cloudflare - пропагация занимает минуты. Для других провайдеров - от 15 минут до нескольких часов в зависимости от TTL. Не переключайте сервер на новый ключ, пока dig не покажет новую запись. Иначе письма будут подписаны ключом, которого принимающий сервер ещё не видит, - и DKIM провалится.
Шаг 3. Переключение сервера
Как именно переключить - зависит от инфраструктуры.
Postfix + OpenDKIM. В конфиге OpenDKIM измените селектор и путь к ключу:
# /etc/opendkim.conf Selector s2 KeyFile /etc/opendkim/keys/dkim_s2_private.pem
# Перезапуск sudo systemctl restart opendkim sudo systemctl restart postfix
Внешний ESP (Mailgun, SendGrid, Postmark). Большинство ESP управляют ключами через панель или API. В Mailgun это раздел «Sending → Domain settings → DKIM». В SendGrid - «Settings → Sender Authentication». Создаёте новый ключ, получаете DNS-запись, добавляете в свой DNS, верифицируете в панели ESP. Некоторые ESP ротируют ключи автоматически и предупреждают по email за неделю.
Проверка после переключения. Отправьте тестовое письмо на Gmail. Откройте «Показать оригинал». В заголовках должен быть новый селектор:
DKIM-Signature: v=1; a=rsa-sha256; d=yourdomain.com; s=s2;
h=from:to:subject:date:message-id;
bh=...;
b=...Authentication-Results: mx.google.com;
dkim=pass header.i=@yourdomain.com header.s=s2Видите s=s2 и dkim=pass? Ротация завершена.
Шаг 4. Удаление старого ключа
Не торопитесь. Письма, отправленные до переключения, могут лежать в retry-очередях принимающих серверов до 72 часов. Некоторые корпоративные серверы проверяют DKIM при повторной доставке. Если к тому моменту старый ключ удалён из DNS - подпись не пройдёт.
Безопасный интервал - 48-72 часа после переключения. После этого удалите TXT-запись для старого селектора из DNS. Приватный ключ - shred или аналог, не просто rm:
# Безвозвратное удаление старого приватного ключа shred -u /etc/opendkim/keys/dkim_s1_private.pem
Автоматизация ротации
Ручная ротация раз в полгода - приемлемо. Но люди забывают. Забыл один раз - ключ живёт уже год. Забыл второй - два года. Автоматизация убирает человеческий фактор.
Минимальный скрипт для ротации (Postfix + OpenDKIM + Cloudflare DNS):
#!/bin/bash
# rotate-dkim.sh - вызывать по cron раз в 6 месяцев
DOMAIN="yourdomain.com"
NEW_SELECTOR="dkim$(date +%Y%m)"
KEY_DIR="/etc/opendkim/keys"
# 1. Генерация нового ключа
openssl genrsa -out "$KEY_DIR/${NEW_SELECTOR}_private.pem" 2048
openssl rsa -in "$KEY_DIR/${NEW_SELECTOR}_private.pem" \
-pubout -out "$KEY_DIR/${NEW_SELECTOR}_public.pem"
chown opendkim:opendkim "$KEY_DIR/${NEW_SELECTOR}_private.pem"
chmod 600 "$KEY_DIR/${NEW_SELECTOR}_private.pem"
# 2. Публичный ключ для DNS
PUBKEY=$(grep -v "^-" "$KEY_DIR/${NEW_SELECTOR}_public.pem" | tr -d '\n')
# 3. Добавить DNS-запись через Cloudflare API
curl -s -X POST \
"https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/dns_records" \
-H "Authorization: Bearer $CF_API_TOKEN" \
-H "Content-Type: application/json" \
--data "{
\"type\": \"TXT\",
\"name\": \"${NEW_SELECTOR}._domainkey.${DOMAIN}\",
\"content\": \"v=DKIM1; k=rsa; p=${PUBKEY}\",
\"ttl\": 300
}"
# 4. Подождать пропагации
sleep 120
# 5. Переключить OpenDKIM
sed -i "s/^Selector.*/Selector ${NEW_SELECTOR}/" /etc/opendkim.conf
sed -i "s|^KeyFile.*|KeyFile $KEY_DIR/${NEW_SELECTOR}_private.pem|" \
/etc/opendkim.conf
systemctl restart opendkim
systemctl restart postfix
echo "DKIM rotated to selector: ${NEW_SELECTOR}"Скрипт намеренно упрощён - в продакшене добавьте проверку dig перед переключением, алерты в Slack/Telegram при ошибках, логирование. Удаление старого ключа из DNS - отдельный скрипт, запускаемый через 72 часа.
Для CI/CD: храните приватные ключи в секретах (Vault, AWS Secrets Manager, GitHub Secrets - не в репозитории). Terraform и Pulumi умеют управлять DNS-записями, интегрируются с пайплайном, и ротация становится частью инфраструктурного кода.
Ошибки, которые ломают ротацию
- Удалили старую DNS-запись до переключения сервера. Сервер подписывает селектором
s1, а записи дляs1уже нет. Все письма проваливают DKIM. Если действуетp=rejectв DMARC - они отклоняются. Это самая частая ошибка при ручной ротации. - Переключили сервер до пропагации DNS. Новая запись ещё не видна принимающим серверам. DKIM тоже провалится. Особенно коварно с DNS-провайдерами, где TTL выставлен в 3600 секунд или выше.
- Забыли про субдомены. Если маркетинговые рассылки идут с
mail.yourdomain.com, а транзакционные - сnotify.yourdomain.com, у каждого свой DKIM-ключ. Ротировать нужно все. - Один селектор для нескольких доменов. Если у вас три домена и все подписываются ключом с селектором
s1, при ротации нужно обновить DNS всех трёх доменов одновременно. Лучше использовать разные селекторы для разных доменов. - Не уничтожили старый приватный ключ. Ротация без уничтожения - полумера. Компрометация старого ключа не поможет подписывать новые письма, но если злоумышленник перехватит письмо в транзите, он сможет подделать подпись задним числом.
Мониторинг после ротации
Первые 24 часа после переключения - критические. Следите за:
- DMARC-отчётами. Если настроен
rua=, агрегированные отчёты покажут, проходят ли письма DKIM с новым селектором. Парсеры (dmarcian, Postmark DMARC, DMARC Analyzer) визуализируют это. - Bounce rate. Резкий рост hard bounce после ротации - сигнал, что что-то пошло не так.
- Логами сервера. OpenDKIM пишет в syslog. Ищите строки с
DKIM-Signatureи проверяйте, что подпись создаётся без ошибок.
# Проверить логи OpenDKIM за последний час journalctl -u opendkim --since "1 hour ago" | grep -i "error\|fail"
Чеклист ротации
Для тех, кто любит списки:
- Сгенерировать новую пару ключей (RSA-2048 или Ed25519).
- Выбрать новый селектор (
s2,dkim202604). - Опубликовать новый публичный ключ в DNS.
- Проверить
dig TXT newSelector._domainkey.yourdomain.com. - Переключить сервер / ESP на новый селектор и ключ.
- Отправить тестовое письмо. Проверить заголовки:
dkim=pass. - Подождать 48-72 часа.
- Удалить старую DNS-запись.
- Уничтожить старый приватный ключ (
shred -u). - Записать дату ротации. Поставить напоминание на следующую (через 6 месяцев).
Как ротация влияет на доставляемость
Прямого влияния на inbox placement нет. Почтовые провайдеры не дают бонусов за частую ротацию. Но влияние косвенное и существенное.
Скомпрометированный ключ - это фишинговые письма с вашей подписью. Получатели нажимают «спам». Репутация домена падает. Доставляемость легитимных писем снижается. Восстановление репутации после такого инцидента занимает недели, иногда месяцы. Ротация - это профилактика. Дешевле менять замок раз в полгода, чем разбираться с последствиями взлома.
Но DKIM - только один слой защиты. Подпись подтверждает подлинность, но не гарантирует качество. Подписанное письмо, отправленное на несуществующий адрес, - всё равно bounce. Подписанное письмо в спам-ловушку - всё равно удар по репутации. Аутентификация и гигиена базы работают в связке.
Ключи ротируются, база стареет
Вы настроили DKIM, ротируете ключи, DMARC на reject. Техническая часть в порядке. Осталось убедиться, что адреса, на которые вы отправляете, ещё живы. За год база теряет до 25% валидных адресов. Проверьте свою.
Загрузите список в uChecker - увидите невалидные адреса, спам-ловушки и рискованные контакты за минуты. 30 бесплатных проверок для старта.
