Перейти к содержимому
ecdsa.com
← Все статьи

Цепочка доверия DNSSEC: DS, DNSKEY, RRSIG и что ломается

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

Коротко. DNSSEC связывает зоны с помощью двух типов записей. Запись DS в родительской зоне содержит хеш ключа подписи ключей (key-signing key, KSK) дочерней зоны: это запись DNSKEY с флагами 257. Этот ключ подписывает набор DNSKEY дочерней зоны, а ключ подписи зоны (zone-signing key, ZSK; флаги 256) подписывает сами записи, и эти подписи публикуются в записях RRSIG. Валидирующий резолвер начинает с корневого ключа, которому доверяет, и проверяет каждое звено вплоть до ответа. Если хотя бы одно звено не проходит проверку, вместо данных резолвер возвращает SERVFAIL. Проверьте цепочку с помощью delv (вывод «fully validated») или dig +dnssec (флаг ad), сравните DS родительской зоны с DNSKEY дочерней утилитой dnssec-dsfromkey, а с +cd выясните, есть ли данные, которые просто не проходят проверку. Большинство сбоев связано со сменой ключей: после смены KSK не обновили запись DS; подписи вовремя не обновили, и срок их действия истёк; ключи сменили быстрее, чем устарели записи в кешах.

Четыре типа записей

ЗаписьГде находитсяЧто содержит
DNSKEYВ самой зонеОткрытые ключи. Флаги 257 обозначают ключ подписи ключей (KSK, установлен бит SEP), 256 — ключ подписи зоны (ZSK)
RRSIGРядом с каждым подписанным набором записейПодпись одного набора записей (RRset) одним ключом; в ней указаны начало и окончание срока действия и тег ключа подписи
DSВ родительской зоне, в точке делегированияДайджест одного из ключей DNSKEY дочерней зоны: тег ключа, алгоритм, тип дайджеста, дайджест
NSEC / NSEC3В зонеПодписанное доказательство того, что имени или типа не существует

Схема разделяет ключи по назначению. KSK подписывает только RRset DNSKEY, а его хеш хранится в родительской зоне. Чтобы сменить KSK, нужно обращаться к родительской стороне (регистратору или реестру). ZSK подписывает всё остальное, и его можно сменить без участия родительской зоны. Зона может использовать для обеих задач и один общий ключ (CSK): именно так работает встроенная в BIND политика dnssec-policy default (csk ... algorithm 13). Правила те же, просто у ключа флаги 257 и он подписывает всё.

Обход реальной цепочки с помощью dig

Пройдём шаг за шагом цепочку для www.isc.org по состоянию на 20 октября 2026 года (dig из BIND 9.20.10, запросы отправлялись на 1.1.1.1). Сначала корень. В его наборе DNSKEY один ZSK и два KSK:

dig . DNSKEY +multiline (сокращено)
.			2158 IN	DNSKEY 256 3 8 (
) ; ZSK; alg = RSASHA256 ; key id = 8763
.			2158 IN	DNSKEY 257 3 8 (
) ; KSK; alg = RSASHA256 ; key id = 20326
.			2158 IN	DNSKEY 257 3 8 (
) ; KSK; alg = RSASHA256 ; key id = 38696

Ключ 20326 — это KSK-2017, а 38696 — KSK-2024. Смена корневого KSK произошла за 9 дней до получения этого вывода. По словам ICANN, «11 октября 2026 года в 14:00 UTC KSK-2024, как и планировалось, начал подписывать корневую зону DNS». Подпись набора DNSKEY корневой зоны это подтверждает:

dig . DNSKEY +dnssec: подпись набора ключей корневой зоны
.			1587 IN	RRSIG DNSKEY 8 0 172800 (
20261101000000 20261011000000 38696 .

Других подписей RRSIG у этого набора нет. Старый ключ всё ещё опубликован и останется в зоне до запланированного отзыва, но больше ничего не подписывает. Резолвер, который доверяет только KSK-2017, потому что так и не получил KSK-2024 ни через автоматическое обновление по RFC 5011, ни с обновлением программного обеспечения, больше ничего не может проверить.

Затем каждое делегирование. Запись DS в родительской зоне указывает на KSK дочерней зоны по тегу ключа:

dig org. DS, dig org. DNSKEY, dig isc.org. DS, dig isc.org. DNSKEY (сокращено)
org.			81000	IN	DS	26974 8 2 4FEDE294C53F438A158C41D39489CD78A86BEB0D8A0AEAFF14745C0D 16E1DE32
) ; ZSK; alg = RSASHA256 ; key id = 25488
) ; ZSK; alg = RSASHA256 ; key id = 11859
) ; ZSK; alg = RSASHA256 ; key id = 24060
) ; KSK; alg = RSASHA256 ; key id = 725
) ; KSK; alg = RSASHA256 ; key id = 26974
isc.org.		3600	IN	DS	7250 13 2 A30B3F78B6DDE9A4A9A2AD0C805518B4F49EC62E7D3F4531D33DE697 CDA01CB2
) ; ZSK; alg = ECDSAP256SHA256 ; key id = 27566
) ; KSK; alg = ECDSAP256SHA256 ; key id = 7250

Запись DS для org. в корневой зоне указывает на ключ 26974, который org. публикует как KSK. Запись DS для isc.org. в зоне org. указывает на ключ 7250 — KSK зоны isc.org. Обратите внимание: по пути вниз меняется алгоритм. org. подписывает данные с помощью RSA (алгоритм 8), а isc.org — с помощью ECDSA P-256 (алгоритм 13). Каждая зона выбирает алгоритм сама. Наконец, сам ответ и его подпись, созданная ZSK 27566 зоны isc.org:

dig www.isc.org. A +dnssec +multiline
www.isc.org.		300 IN A 151.101.3.42
www.isc.org.		300 IN A 151.101.67.42
www.isc.org.		300 IN A 151.101.131.42
www.isc.org.		300 IN A 151.101.195.42
www.isc.org.		300 IN RRSIG A 13 3 300 (
				20261103074926 20261020065242 27566 isc.org.
				qz5Qb4BFyOw4PRXBJjeK61LrPSKo6G2Ma1aFwNwZ57x5
				bFIg/d3EoMHtXopLYU949QQtMjcQ8BWULk7a629tLA== )

Поля RRSIG: покрываемый тип A, алгоритм 13, число меток 3, исходный TTL 300, окончание срока действия 2026-11-03 07:49:26 UTC, начало срока действия 2026-10-20 06:52:42 UTC, тег ключа 27566, подписант isc.org.. Валидирующий резолвер, который проверил всё это, устанавливает флаг AD (authenticated data, аутентифицированные данные):

dig www.isc.org A +dnssec @1.1.1.1
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 5, AUTHORITY: 0, ADDITIONAL: 1

Флаг ad — лишь утверждение резолвера, и доверять ему можно не больше, чем пути до этого резолвера. Чтобы проверить цепочку самостоятельно, используйте delv: он проходит её целиком локально, опираясь на встроенные корневые якоря доверия. Параметр +rtrace показывает, какие запросы выполняются:

delv @1.1.1.1 www.isc.org A +rtrace (BIND 9.20.10, сокращено)
;; fetch: www.isc.org/A
;; fetch: isc.org/DNSKEY
;; fetch: isc.org/DS
;; fetch: org/DNSKEY
;; fetch: org/DS
;; fetch: ./DNSKEY
; fully validated

Параметра dig +sigchase, который советуют старые руководства, больше нет: dig 9.20 отвечает dig: +sigchase option no longer supported. Используйте delv. Чтобы пройти ту же цепочку в браузере через DNS-over-HTTPS, откройте инспектор DNSSEC: он запрашивает каждое звено, проверяет каждую подпись RRSIG собственным кодом и указывает звено, на котором цепочка рвётся.

Алгоритмы 8, 13 и 15

Номер алгоритма указывается в записях DNSKEY, DS и RRSIG. RFC 9904 (ноябрь 2025 года) заменил RFC 8624 и перенёс рекомендации прямо в реестр IANA; RFC 9905, опубликованный вместе с ним, запрещает подписание двумя алгоритмами на основе SHA-1:

НомерАлгоритмПодписаниеПроверка
5, 7RSA/SHA-1Запрещено (MUST NOT)Реализация обязательна (MUST); операторы резолверов считают его неподдерживаемым
8RSA/SHA-256Рекомендуется (RECOMMENDED), реализация обязательна (MUST)Реализация обязательна (MUST)
10RSA/SHA-512Не рекомендуется (NOT RECOMMENDED)Реализация обязательна (MUST)
13ECDSA P-256/SHA-256Рекомендуется (RECOMMENDED), реализация обязательна (MUST)Реализация обязательна (MUST)
14ECDSA P-384/SHA-384Допускается (MAY)Рекомендуется (RECOMMENDED)
15Ed25519Рекомендуется (RECOMMENDED)Рекомендуется (RECOMMENDED)
16Ed448Допускается (MAY)Рекомендуется (RECOMMENDED)

Для дайджестов DS следует использовать SHA-256 (тип 2). Для делегирований SHA-1 (тип 1) имеет статус «MUST NOT», то есть запрещён, хотя валидаторы по-прежнему обязаны его поддерживать. Из 10 зон, которые мы проверили 20 октября 2026 года, com., net., nl., cloudflare.com, isc.org, ietf.org, nic.cz и sidn.nl подписаны алгоритмом 13, а org. и de. — алгоритмом 8, как и корневая зона. Если подписать одну и ту же зону каждым из алгоритмов, станет видно, почему алгоритм 13 так популярен:

dnssec-keygen / dnssec-signzone 9.20.29: одна зона, три алгоритма
algorithm 8  RSASHA256         ZSK public key 260 bytes, RRSIG signature 256 bytes
algorithm 13 ECDSAP256SHA256   ZSK public key  64 bytes, RRSIG signature  64 bytes
algorithm 15 ED25519           ZSK public key  32 bytes, RRSIG signature  64 bytes

Небольшие подписи позволяют ответам укладываться в ограничение размера UDP (сегодня типичный размер буфера EDNS — 1232 байта), и тогда не возникает ни фрагментации, ни перехода на TCP. У алгоритма 15 самые маленькие ключи, но его поддержка валидаторами лишь рекомендуется (RECOMMENDED), а не обязательна (MUST), поэтому, прежде чем выбрать его, проверьте резолверы своей аудитории.

Намеренно ломаем цепочку

На тестовом стенде ниже работают два экземпляра BIND 9.20.29 на Debian 13: так сбои можно увидеть, не ломая настоящий домен. Первый — авторитетный сервер для собственной корневой зоны ., а также для lab. и shop.lab.; все три зоны подписаны алгоритмом 13. Второй — валидирующий резолвер, единственный якорь доверия которого — запись DS этой собственной корневой зоны. Ключи создаются и зоны подписываются обычными утилитами BIND:

Фрагмент скрипта стенда: ключи, подписание и якорь доверия резолвера
keygen() { dnssec-keygen -q -K keys -a ECDSAP256SHA256 -L 3600 "$@"; }
for z in . lab shop.lab; do keygen -fKSK "$z" >/dev/null; keygen "$z" >/dev/null; done

# the parent includes the child's dsset file before signing
cat auth/db.lab.unsigned auth/dsset-shop.lab. > auth/db.lab
dnssec-signzone -q -S -K keys -d auth -o lab -f auth/db.lab.signed auth/db.lab

read -r _ _ _ tag alg dt d1 d2 < auth/dsset-.
echo "trust-anchors { . static-ds $tag $alg $dt \"$d1$d2\"; };" > anchors.conf

1. Всё настроено правильно. Запись DS в lab. указывает на KSK зоны shop.lab., резолвер устанавливает ad, а delv успешно проверяет ответ:

Стенд, случай 1
DS in lab.: shop.lab. 48794 13 2
DNSKEY in shop.lab.: ZSK; alg = ECDSAP256SHA256 ; key id = 6251
DNSKEY in shop.lab.: KSK; alg = ECDSAP256SHA256 ; key id = 48794
$ dig @127.0.0.1 www.shop.lab A +dnssec
;; ->>HEADER<<- opcode: QUERY, status: NOERROR
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
www.shop.lab.		5	IN	A	192.0.2.10
$ delv @127.0.0.2 -a anchors.conf www.shop.lab A
; fully validated
www.shop.lab.		5	IN	A	192.0.2.10

2. KSK в дочерней зоне заменён, а DS в родительской не обновлена. Это классический сбой после переезда к другому DNS-хостингу или после автоматической смены KSK, которую никто не довёл до конца у регистратора:

Стенд, случай 2
DS in lab.: shop.lab. 48794 13 2
DNSKEY in shop.lab.: KSK; alg = ECDSAP256SHA256 ; key id = 11943
DNSKEY in shop.lab.: ZSK; alg = ECDSAP256SHA256 ; key id = 6251
$ dig @127.0.0.1 www.shop.lab A +dnssec
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1
$ dig @127.0.0.1 www.shop.lab A +dnssec +cd
;; ->>HEADER<<- opcode: QUERY, status: NOERROR
;; flags: qr rd ra cd; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
www.shop.lab.		5	IN	A	192.0.2.10
$ delv @127.0.0.2 -a anchors.conf www.shop.lab A
;; validating shop.lab/DNSKEY: no valid signature found (DS)
;; broken trust chain resolving 'www.shop.lab/A/IN': 127.0.0.2#53
;; resolution failed: broken trust chain

В DS по-прежнему указан ключ 48794, а у зоны теперь KSK 11943. С +cd (checking disabled, проверка отключена) резолвер возвращает данные, а значит, зона работает и не проходит только проверка. Это самый быстрый способ отличить сбой DNSSEC от недоступности зоны.

3. Срок действия подписей истёк. Запись DS исправлена, но зону подписали один раз и больше не переподписывали. Здесь стенд подписывает её так, что срок действия подписей начался 10 дней назад и истёк час назад:

Стенд, случай 3
RRSIG inception 20261010131152 expiration 20261020121152
$ dig @127.0.0.1 www.shop.lab A +dnssec
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1
; EDE: 7 (Signature Expired): (shop.lab/DNSKEY)
$ delv @127.0.0.2 -a anchors.conf www.shop.lab A
;; validating shop.lab/DNSKEY: no valid signature found (DS)
;; broken trust chain resolving 'www.shop.lab/A/IN': 127.0.0.2#53
;; resolution failed: broken trust chain

BIND добавляет к ответу расширенную ошибку DNS (Extended DNS Error, RFC 8914), которая называет причину: EDE: 7 (Signature Expired). При статическом подписании через dnssec-signzone подписи по умолчанию действуют 30 дней (при первом подписании на стенде получились начало срока действия 20261020120639 и окончание 20261119120639), поэтому задание cron, которое перестало переподписывать зону, через месяц приведёт ровно к такому сбою. Вместо этого пусть DNS-сервер сам подписывает и переподписывает зону: в BIND для этого есть dnssec-policy, которая по умолчанию каждые 5 дней обновляет подписи, действующие 14 дней, а в Knot и PowerDNS — аналогичные механизмы.

4. ZSK заменён за один шаг. Зона заменяет свой ZSK и сразу переподписывает все данные новым ключом. Резолвер, который закешировал старый набор DNSKEY (TTL 3600), получает запись A, подписанную ключом, которого у него нет:

Стенд, случай 4
$ dig @127.0.0.1 www.shop.lab A +dnssec
;; ->>HEADER<<- opcode: QUERY, status: NOERROR
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
www.shop.lab.		5	IN	A	192.0.2.10
resolver cache: DNSKEY flags 256 TTL 3600
resolver cache: DNSKEY flags 257 TTL 3600
(6 s later: the A record's 5 s TTL has expired, the cached DNSKEY set's 3600 s TTL has not)
$ dig @127.0.0.1 www.shop.lab A +dnssec
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1
(resolver restarted, cache empty)
$ dig @127.0.0.1 www.shop.lab A +dnssec
;; ->>HEADER<<- opcode: QUERY, status: NOERROR
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
www.shop.lab.		5	IN	A	192.0.2.10

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

Смена ключей без сбоев

RFC 6781 описывает безопасные последовательности действий. В основе их всех лежит одно правило: любой резолвер должен успешно проверять данные, какое бы сочетание старых и новых записей ни лежало у него в кеше.

  • ZSK, предварительная публикация (pre-publish). Добавьте новый ZSK в набор DNSKEY, пока старый ещё подписывает данные. Подождите не меньше TTL записей DNSKEY, чтобы оба ключа оказались во всех кешах. Переключите подписание на новый ключ. Подождите, пока истечёт самый длинный TTL подписанных данных и старые подписи уйдут из кешей. Затем удалите старый ключ.
  • KSK, двойная подпись (double-signature). Добавьте новый KSK и подпишите набор DNSKEY обоими ключами. Передайте новую запись DS в родительскую зону. Дождитесь, пока родительская зона её опубликует, а старая DS исчезнет из кешей (TTL записи DS, часто час или сутки). Только после этого удалите старый KSK.
  • Смена алгоритма (например, с 8 на 13). Новые ключи нового алгоритма должны подписать всё до появления новой записи DS, а старый алгоритм должен продолжать подписывать данные, пока старая DS не исчезнет. Полная последовательность приведена в RFC 6781, § 4.1.4.
  • Автоматизируйте шаг родительской зоны. Записи CDS и CDNSKEY (RFC 8078) позволяют родительской зоне, которая их поддерживает, получать новую DS из дочерней. Без них шаг с DS выполняется у регистратора вручную, и именно на нём смена ключей застревает.
  • Переход к другому DNS-провайдеру. Либо выполните согласованный переезд по схеме с несколькими подписантами (multi-signer), либо сначала удалите DS у регистратора, дождитесь истечения её TTL и снова включите DNSSEC с ключом нового провайдера. Перенос записей NS при оставшейся старой DS — это случай 2, только в рабочей среде.

dnssec-policy в BIND и менеджеры ключей в Knot и PowerDNS соблюдают эти интервалы за вас. Чаще всего подводит не инструмент, а шаг с родительской зоной: запись DS, которую нужно вставить в веб-форму регистратора.

Диагностика SERVFAIL

  1. Дело в DNSSEC? dig name +cd возвращает данные, а dig name выдаёт SERVFAIL → ошибка проверки. Найдите строку EDE: 6 (DNSSEC Bogus), 7 (Signature Expired), 8 (Signature Not Yet Valid), 9 (DNSKEY Missing), 10 (RRSIGs Missing).
  2. Какое звено? Запустите delv name +rtrace и найдите первый шаг с ошибкой.
  3. Сверка DS и DNSKEY: вычислите DS по ключам дочерней зоны и сравните с записью в родительской:
DS в родительской зоне и DS, вычисленная по DNSKEY дочерней зоны (bind9-utils 9.20.29)
$ dig +short DS isc.org @1.1.1.1
7250 13 2 A30B3F78B6DDE9A4A9A2AD0C805518B4F49EC62E7D3F4531D33DE697 CDA01CB2
$ dig +cd +noall +answer DNSKEY isc.org @1.1.1.1 | dnssec-dsfromkey -2 -f - isc.org
isc.org. IN DS 7250 13 2 A30B3F78B6DDE9A4A9A2AD0C805518B4F49EC62E7D3F4531D33DE697CDA01CB2
$ dig +short DS dnssec-failed.org @1.1.1.1
42069 13 2 62726F6B656E20636861696E206F662074727573742073656E642068 656C7021
$ dig +cd +noall +answer DNSKEY dnssec-failed.org @1.1.1.1 | dnssec-dsfromkey -2 -f - dnssec-failed.org
dnssec-failed.org. IN DS 50719 13 2 D602C971A02AF89B7661B99D6DD1B9E2EC876617631D04F633902A42CD4D6BBD

У isc.org записи совпадают. dnssec-failed.org — намеренно сломанный тестовый домен, который обслуживают DNS-серверы Comcast (dns101.comcast.net и другие). Его DS указывает на несуществующий ключ 42069, а дайджест в ASCII читается как «broken chain of trust send help!». Публичные резолверы, как и положено, его отклоняют:

dig @1.1.1.1 dnssec-failed.org A
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 59477
; EDE: 9 (DNSKEY Missing): (no SEP matching the DS found for dnssec-failed.org.)
  1. Время подписей: сравните начало и окончание срока действия RRSIG с текущим временем UTC. Если часы у подписанта или валидатора идут неправильно, подписи оказываются ещё не действительными или уже просроченными.
  2. Сбои, зависящие от резолвера, после смены ключа указывают на кеширование (случай 4). Проверьте TTL наборов DNSKEY и DS и время смены.

Что даёт DNSSEC

Работающая цепочка доверия — основа для записей, которым нужна подлинность, а не только доступность. DANE/TLSA закрепляет ключи TLS в DNS и применяется для SMTP между почтовыми серверами. Такие записи создаёт генератор записей TLSA. Центры сертификации (CA) проверяют записи CAA, а с 15 марта 2026 года требования CA/Browser Forum (Baseline Requirements) обязывают проверять DNSSEC при запросе записей CAA, если зона подписана. Поэтому разорванная цепочка может заблокировать и выпуск сертификатов.

Источники

  • RFC 4033, RFC 4034, RFC 4035: введение в DNSSEC, записи, протокол.
  • RFC 9904: порядок обновления рекомендаций по алгоритмам DNSSEC (ноябрь 2025 года).
  • RFC 9905: отказ от SHA-1 в алгоритмах подписи DNSSEC (ноябрь 2025 года).
  • RFC 6781: практика эксплуатации DNSSEC, смена ключей. RFC 8078: CDS/CDNSKEY.
  • RFC 8914: расширенные ошибки DNS (Extended DNS Errors).
  • ICANN, смена KSK корневой зоны.

Запросы к реальным зонам выполнялись 20 октября 2026 года в nicolaka/netshoot:v0.14 (dig и delv из BIND 9.20.10). Стенд и dnssec-dsfromkey работали в debian:trixie-20261005-slim с BIND 9.20.29 из Debian.