today keys : DNSSEC, 키 롤오버, ZSK, KSK, Pre-Publish, Double-DS, CDS, CDNSKEY, 알고리즘 교체
DNSSEC 운영에서 발생하는 사고는 대부분 두 가지에서 나옵니다. 재서명을 놓쳐 서명이 만료되는 경우, 그리고 키를 교체하다 신뢰 사슬을 끊어먹는 경우입니다. 앞의 것은 자동화로 해결되지만 뒤의 것은 절차를 이해하고 있어야 합니다.
이번 편에서는 키 롤오버를 다룹니다. 왜 단순히 키를 바꿔 끼우면 안 되는지, ZSK와 KSK의 절차가 왜 다른지, 그리고 순서를 어기면 어떤 일이 벌어지는지 정리하겠습니다.
1. 왜 키를 교체하는가
키 교체가 필요한 이유는 세 가지입니다.
유출 대비 — 개인키가 오래 사용될수록 노출 위험이 누적됩니다. 정기 교체는 만약의 유출이 있더라도 피해 기간을 제한합니다.
유출 발생 시 긴급 대응 — 실제로 개인키가 유출됐다면 즉시 교체해야 합니다. 이 경우는 정기 교체와 달리 대기 시간을 충분히 둘 여유가 없습니다.
알고리즘 전환 — RSA에서 ECDSA로 옮기는 경우처럼, 더 짧고 효율적인 알고리즘으로 이전할 때도 키를 바꿔야 합니다.
앞서 살펴본 대로 ZSK와 KSK는 교체 주기가 다릅니다.
| 구분 | ZSK | KSK |
| 일반적 주기 | 1~3개월 | 1년 이상 |
| 교체 범위 | 존 내부에서 완결 | 부모 존의 DS 재등록 필요 |
| 난이도 | 낮음 | 높음 |
이 차이가 키를 둘로 나눈 이유이기도 합니다.
자주 바꿔야 하는 쪽은 외부 절차 없이 처리하고, 외부 절차가 필요한 쪽은 거의 바꾸지 않도록 역할을 분리한 것입니다.
2. 롤오버가 어려운 이유 - 캐시
키를 바꾸는 일 자체는 간단합니다. 새 키를 만들고 그 키로 다시 서명하면 됩니다. 문제는 전 세계 리졸버의 캐시입니다.
DNS 응답은 TTL 동안 캐시에 남습니다. 그런데 서명과 키가 각각 따로 캐시되기 때문에, 교체 과정에서 이런 상황이 생길 수 있습니다.
권한 서버 : 새 ZSK로 서명한 A 레코드를 응답
리졸버 캐시 : 예전에 받아둔 DNSKEY (구 ZSK만 들어 있음)
↓
새 서명을 검증할 공개키가 캐시에 없음
↓
검증 실패 → bogus → SERVFAIL
반대로 키는 새것인데 서명이 옛것인 경우도 마찬가지입니다. 어느 쪽이든 결과는 도메인 전체가 조회되지 않는 상황입니다.
이 문제를 피하는 원칙은 하나입니다.
📌 한 줄 요약: 새것을 먼저 추가하고, 캐시가 비워질 때까지 기다린 뒤, 전환하고, 다시 기다린 다음 옛것을 제거합니다. 추가가 먼저, 제거가 나중입니다.
3. ZSK 롤오버 - Pre-Publish 방식
ZSK는 존 내부에서만 처리되므로 비교적 단순합니다. 표준적인 방식이 Pre-Publish로, 새 키를 미리 게시해두는 것이 핵심입니다.
1단계 : 새 ZSK를 DNSKEY에 추가 게시
zigispace.net. DNSKEY 257 3 13 ... ← KSK (변동 없음)
zigispace.net. DNSKEY 256 3 13 ... ← 구 ZSK (12345), 서명은 계속 이 키로
zigispace.net. DNSKEY 256 3 13 ... ← 신 ZSK (67890), 추가만 해둠
이 시점에는 서명 주체를 바꾸지 않습니다. 레코드의 RRSIG는 여전히 구 ZSK가 만듭니다. 새 키는 DNSKEY RRset에 자리만 잡아둔 상태입니다.
이 구간에서 리졸버가 어떤 상태에 있든 검증에는 문제가 없습니다.
| 리졸버의 DNSKEY 캐시 | 받은 서명 | 결과 |
| 구 ZSK(12345)만 보유 | 12345로 서명 | 검증 성공 |
| 구 12345 + 신 67890 보유 | 12345로 서명 | 검증 성공 |
신 키를 이미 받은 리졸버는 ZSK를 두 개 갖고 있게 되는데, 어느 키로 검증할지는 RRSIG의 Key Tag 필드가 알려줍니다.
www.zigispace.net. RRSIG A 13 3 300 ... 12345 zigispace.net.
└─ 이 태그의 키로 검증하라
리졸버는 캐시된 DNSKEY RRset에서 태그가 12345인 키를 골라 사용합니다.
신 ZSK가 함께 있어도 아직 쓰이지 않을 뿐, 혼란을 일으키지 않습니다.
2단계 : DNSKEY RRset의 TTL만큼 대기
전 세계 리졸버의 캐시에 새 키가 포함된 DNSKEY가 퍼지기를 기다립니다.
DNSKEY의 TTL이 3600초라면 최소 그만큼은 기다려야 합니다.
3단계 : 서명 주체를 신 ZSK로 전환
www.zigispace.net. A 10.10.10.10
www.zigispace.net. RRSIG A ... 67890 zigispace.net. ← 신 ZSK로 재서명
이제 새 서명이 나가기 시작합니다. 여기서 앞 구간과 상황이 갈립니다.
| 리졸버의 DNSKEY 캐시 | 받은 서명 | 결과 |
| 구 12345 + 신 67890 보유 | 67890으로 서명 | 검증 성공 |
| 구 ZSK(12345)만 보유 | 67890으로 서명 | 태그 67890 키 없음 → bogus |
아래쪽이 문제가 되는 상태입니다.
Key Tag가 67890인데 캐시에 그 키가 없으니 검증할 수단이 없고, 결과는 SERVFAIL입니다.
2단계에서 DNSKEY TTL만큼 기다린 이유가 바로 이것입니다.
아래쪽 상태의 리졸버를 세상에서 없애는 작업이었던 셈입니다.
대기가 끝난 시점에는 모든 리졸버의 DNSKEY 캐시가 한 번 갱신되어 신 ZSK를 갖고 있으므로, 전환해도 안전합니다.
참고로 "캐시에 맞는 키가 없으면 DNSKEY를 다시 물어보면 되지 않나" 생각할 수 있고 실제로 그렇게 동작하는 구현도 있습니다. 다만 캐시된 DNSKEY RRset은 TTL 동안 유효한 데이터이므로, 검증기가 그것만 보고 실패로 판정해도 프로토콜상 문제가 없습니다. 구현마다 다른 동작에 안전성을 맡길 수 없어 대기 시간으로 확실하게 처리하는 것입니다.
4단계 : 기존 RRSIG의 최대 TTL만큼 대기
캐시에 남아 있는 구 ZSK 서명들이 만료되기를 기다립니다. 구 ZSK로 서명된 RRSIG가 아직 캐시에 남아 있는데 키를 먼저 지워버리면, 이번에는 반대 방향으로 같은 문제가 생기기 때문입니다.
두 번의 대기는 방향만 다를 뿐 원리가 같습니다.
2단계 대기 : 새 키가 모두에게 퍼질 때까지 (키가 먼저, 서명이 나중)
4단계 대기 : 옛 서명이 모두 사라질 때까지 (서명이 먼저, 키가 나중)
제거할 대상보다 그것을 필요로 하는 데이터가 먼저 사라지도록 순서를 맞추는 것입니다.
5단계 : 구 ZSK를 DNSKEY에서 제거
이제 안전하게 제거할 수 있습니다.
새 키 추가 → DNSKEY TTL 대기 → 서명 전환 → RRSIG TTL 대기 → 구 키 제거
전체 소요 시간은 TTL 설정에 따라 수 시간에서 하루 정도입니다.
4. KSK 롤오버 - Double-DS 방식
KSK는 상황이 다릅니다. 앞서 다룬 대로 KSK의 해시가 부모 존에 DS로 등록되어 있기 때문에, 내 존만 바꿔서는 끝나지 않습니다. 부모 쪽 갱신이 함께 이루어져야 하고, 그 반영 시점을 내가 통제할 수 없습니다.
그래서 부모 쪽을 먼저 준비시키는 Double-DS 방식을 씁니다.
1단계 : 새 KSK의 DS를 부모에 추가 등록
레지스트라 콘솔에서 DS를 교체하는 것이 아니라 추가합니다. 이 시점에 부모 존에는 DS가 두 개 존재합니다.
zigispace.net. DS 45678 13 2 4F7A2B91... ← 구 KSK의 DS
zigispace.net. DS 24680 13 2 9C3D5E77... ← 신 KSK의 DS (추가)
내 존에는 아직 아무 변화가 없습니다. 새 KSK는 만들어만 두고 게시하지 않은 상태입니다.
2단계 : 부모 DS의 TTL만큼 대기
리졸버 캐시에 두 DS가 모두 퍼지기를 기다립니다.
TLD의 DS TTL은 보통 86400초(하루)이므로, ZSK 롤오버보다 대기 시간이 깁니다.
이 구간에서는 내 존이 그대로이므로 어느 리졸버든 정상입니다.
| 리졸버의 DS 캐시 | 존의 KSK | 결과 |
| 구 DS(45678)만 보유 | 구 KSK(45678) | 검증 성공 |
| 구 + 신 DS 보유 | 구 KSK(45678) | 구 DS와 매칭되어 검증 성공 |
DS가 여러 개일 때 리졸버는 그중 하나라도 매칭되면 통과시킵니다.
신 DS가 함께 있어도 대응하는 KSK가 아직 존에 없을 뿐, 문제가 되지 않습니다.
3단계 : 존의 KSK를 신규로 교체
zigispace.net. DNSKEY 257 3 13 ... ← 신 KSK (24680)
zigispace.net. DNSKEY 256 3 13 ... ← ZSK (변동 없음)
zigispace.net. RRSIG DNSKEY ... 24680 ← 신 KSK로 서명
여기서 리졸버 상태별로 결과가 갈립니다.
| 리졸버의 DS 캐시 | 존의 KSK | 결과 |
| 구 + 신 DS 보유 | 신 KSK(24680) | 신 DS와 매칭되어 검증 성공 |
| 구 DS(45678)만 보유 | 신 KSK(24680) | 매칭되는 DS 없음 → bogus |
아래쪽이 위험한 상태입니다. 캐시에 구 DS만 있는데 존에서 구 KSK가 사라졌다면 대조할 대상이 없습니다.
2단계에서 DS TTL만큼 기다린 이유가 이것으로, 그 대기가 끝나면 모든 리졸버가 신 DS를 갖게 되어 위쪽 상태만 남습니다.
여기에 더해 3단계에서 구 KSK도 함께 게시해두면 한층 안전합니다.
부모에 DS가 둘 다 있고 존에도 KSK가 둘 다 있으므로, 리졸버가 어느 조합을 갖고 있든 매칭되는 짝이 존재하게 됩니다.
ZSK 롤오버와 비교하면 축이 하나 늘어난 것뿐입니다.
ZSK는 DNSKEY 캐시 하나만 신경 쓰면 됐지만, KSK는 부모의 DS 캐시와 자식의 DNSKEY라는 두 축을 맞춰야 합니다.
내가 통제할 수 없는 부모 쪽을 먼저 준비시키는 이유입니다.
4단계 : DS TTL 경과 후 구 DS 제거
레지스트라에서 구 KSK의 DS를 삭제합니다. 이후 구 KSK도 존에서 제거하면 완료됩니다.
신 DS 추가 → DS TTL 대기 → 존 KSK 교체 → DS TTL 대기 → 구 DS 제거
대안 : Double-Signature 방식
부모의 DS TTL이 지나치게 길거나 레지스트라가 DS를 하나만 받는 경우에는 순서를 반대로 합니다.
신 KSK를 존에 추가 게시 (두 KSK로 DNSKEY 서명)
↓ DNSKEY TTL 대기
부모의 DS를 신 KSK 것으로 교체
↓ DS TTL 대기
구 KSK 제거
어느 방식이든 원칙은 같습니다. 양쪽 중 한쪽을 먼저 준비시키고, 캐시가 도는 시간을 기다린 뒤 나머지를 바꿉니다.
5. 순서를 어기면 생기는 일
가장 흔한 사고 유형은 "그냥 바꿔버리는 것"입니다. 새 키를 만들어 존을 재서명하고 DS를 교체하는 작업을 동시에 해버리는 경우입니다.
관리자가 KSK 교체 + DS 교체를 한꺼번에 수행
↓
리졸버 A : 캐시에 구 DS 보유 → 존에는 신 KSK만 존재 → 대조 실패
리졸버 B : 신 DS 수신 → 캐시에 구 DNSKEY 보유 → 대조 실패
↓
양쪽 모두 bogus 판정 → SERVFAIL
↓
TTL이 만료될 때까지 도메인 전체 조회 불가
4부에서 확인한 대로 bogus는 응답을 차단합니다.
서비스가 느려지는 정도가 아니라 아예 접속이 되지 않습니다.
그리고 캐시가 자연히 비워질 때까지 기다리는 것 외에는 즉시 복구할 방법이 마땅치 않습니다.
실습에서 사용한 dnssec-failed.org가 바로 이 상태를 재현해둔 도메인입니다.
부모에 DS는 있는데 그에 대응하는 DNSKEY가 자식 존에 없어 EDE 9 (DNSKEY Missing)이 반환됩니다.
6. CDS / CDNSKEY - DS 갱신 자동화
KSK 롤오버가 번거로운 근본 원인은 DS 등록이 레지스트라를 거치는 수동 절차라는 점입니다.
사람이 콘솔에 값을 입력해야 하니 자동화가 어렵고 실수도 발생합니다.
이를 해결하기 위한 것이 CDS와 CDNSKEY 레코드입니다.
자식 존이 "내 DS를 이 값으로 바꿔달라"는 요청을 자기 존 안에 게시하면, 부모가 이를 주기적으로 확인해 반영하는 방식입니다.
자식 존이 CDS 레코드를 게시
zigispace.net. CDS 24680 13 2 9C3D5E77...
↓
레지스트리 또는 레지스트라가 주기적으로 이 값을 조회
↓
기존 DNSSEC 체인으로 이 CDS의 서명을 검증
↓
검증 통과 시 부모 존의 DS를 자동 갱신
핵심은 이 요청 자체가 기존 키로 서명되어 있다는 점입니다.
아무나 CDS를 게시해서 남의 DS를 바꿀 수는 없습니다.
CDS는 DS 형식으로, CDNSKEY는 DNSKEY 형식으로 값을 전달하는 차이가 있을 뿐 목적은 같습니다.
부모 쪽이 어느 형식을 받는지에 따라 선택하거나 둘 다 게시합니다.
다만 지원 범위가 아직 제한적입니다.
일부 ccTLD와 일부 레지스트라만 이 방식을 지원하며, .com을 비롯한 다수 gTLD는 여전히 수동 등록이 기본입니다.
사용 중인 레지스트라가 지원하는지 확인이 필요합니다.
7. 알고리즘 교체
키만 바꾸는 것이 아니라 알고리즘 자체를 바꾸는 경우가 있습니다. 실무에서는 주로 RSA에서 ECDSA로 옮기는 방향입니다.
| 번호 | 알고리즘 | 서명 길이 | 특징 |
| 8 | RSA / SHA-256 | 약 256바이트 | 가장 널리 쓰이나 응답이 큼 |
| 13 | ECDSA P-256 | 64바이트 | 현재 권장, 응답 크기 대폭 감소 |
| 15 | Ed25519 | 64바이트 | 최신, 지원 범위 확산 중 |
응답 크기가 줄어드는 것이 실질적인 이점입니다.
DNSSEC 응답은 서명 때문에 커지는데, UDP 크기를 넘으면 TCP로 재시도하게 되어 지연이 늘어납니다.
ECDSA는 서명 길이가 4분의 1 수준이라 이 문제를 크게 완화합니다.
알고리즘 교체가 까다로운 이유
일반 키 롤오버와 달리 규칙이 하나 더 붙습니다. 존에 존재하는 모든 알고리즘으로 모든 RRset이 서명되어 있어야 합니다.
알고리즘 8과 13이 동시에 존재하는 기간
↓
모든 RRset에 RRSIG가 두 개씩 붙어야 함 (알고리즘 8용, 알고리즘 13용)
↓
전환 기간 동안 존 크기와 응답 크기가 일시적으로 증가
이 조건을 지키지 않으면 일부 리졸버가 "지원하는 알고리즘의 서명이 없다"고 판단해 검증에 실패할 수 있습니다.
전환 순서는 다음과 같습니다.
신 알고리즘 키 생성 → 두 알고리즘으로 모든 RRset 서명 → DNSKEY에 신 키 추가
↓ TTL 대기
부모 DS를 신 알고리즘 것으로 교체
↓ TTL 대기
구 알고리즘 서명과 키 제거
대부분의 DNS 소프트웨어가 이 절차를 자동으로 처리해주므로 직접 수행할 일은 많지 않습니다.
다만 전환 중에 응답 크기가 늘어난다는 점은 알고 계시는 편이 좋습니다.
8. 직접 확인해보기
롤오버 진행 중인지 확인하기
DNSKEY가 세 개 이상이면 롤오버가 진행 중일 가능성이 높습니다.
dig cloudflare.com DNSKEY +short
평상시에는 257(KSK) 하나와 256(ZSK) 하나로 두 줄이지만, ZSK 롤오버 중에는 256이 두 개 나타납니다.
KSK 롤오버 중이면 257이 두 개가 됩니다.
부모의 DS 개수 확인하기
dig cloudflare.com DS +short
DS가 두 개 나오면 KSK 롤오버의 Double-DS 구간에 있다는 의미입니다.
다만 하나의 KSK에 대해 다이제스트 타입을 여러 개 등록한 경우에도 DS가 여러 개가 되므로, Key Tag 값이 서로 다른지를 함께 확인해야 합니다.
2371 13 2 32996839A6D8... ← Key Tag 2371
2371 13 4 8ACBB0CD28F4... ← 같은 키, 다이제스트 타입만 다름 (롤오버 아님)
CDS 게시 여부 확인하기
dig cloudflare.com CDS +short
dig cloudflare.com CDNSKEY +short
값이 나오면 자동 DS 갱신을 지원하는 구성입니다. 아무것도 출력되지 않으면 수동 등록 방식을 쓰고 있다는 뜻입니다.
zigi@ZIGI:~$ dig @8.8.8.8 cloudflare.com CDS +short
2371 13 2 32996839A6D808AFE3EB4A795A0E6A7A39A76FC52FF228B22B76F6D6 3826F2B9
zigi@ZIGI:~$ dig @8.8.8.8 cloudflare.com CDNSKEY +short
257 3 13 mdsswUyr3DPW132mOi8V9xESWE8jTo0dxCjjnopKl+GqJxpVXckHAeF+ KkxLbxILfDLUT0rAK9iUzy1L53eKGQ==
루트 키 상태 보기
dig . DNSKEY +short
루트도 같은 원리로 관리됩니다. ZSK는 주기적으로 교체되므로 시점에 따라 256이 두 개 보일 수 있습니다.
zigi@ZIGI:~$ dig @8.8.8.8 . DNSKEY +short
257 3 8 AwEAAaz/tAm8yTn4Mfeh5eyI96WSVexTBAvkMgJzkKTOiW1vkIbzxeF3 +/4RgWOq7HrxRixHlFlExOLAJr5emLvN7SWXgnLh4+B5xQlNVz8Og8kv ArMtNROxVQuCaSnIDdD5LKyWbRd2n9WGe2R8PzgCmr3EgVLrjyBxWezF 0jLHwVN8efS3rCj/EWgvIWgb9tarpVUDK/b58Da+sqqls3eNbuv7pr+e oZG+SrDK6nWeL3c6H5Apxz7LjVc1uTIdsIXxuOLYA4/ilBmSVIzuDWfd RUfhHdY6+cn8HFRm+2hM8AnXGXws9555KrUB5qihylGa8subX2Nn6UwN R1AkUTV74bU=
257 3 8 AwEAAa96jeuknZlaeSrvyAJj6ZHv28hhOKkx3rLGXVaC6rXTsDc449/c idltpkyGwCJNnOAlFNKF2jBosZBU5eeHspaQWOmOElZsjICMQMC3aeHb GiShvZsx4wMYSjH8e7Vrhbu6irwCzVBApESjbUdpWWmEnhathWu1jo+s iFUiRAAxm9qyJNg/wOZqqzL/dL/q8PkcRU5oUKEpUge71M3ej2/7CPqp dVwuMoTvoB+ZOT4YeGyxMvHmbrxlFzGOHOijtzN+u1TQNatX2XBuzZNQ 1K+s2CXkPIZo7s6JgZyvaBevYtxPvYLw4z9mR7K2vaF18UYH9Z9GNUUe ayffKC73PYc=
256 3 8 AwEAAeCYD6Z7WWKVLeuWgowKP+3g+Gs1cnLKq7a3CaQxQpv8bfuFVI0W nG33qaSH/Mw9IBgifrdzf4XY/DQLnyBJ9MfaOyAWuEaEmYJ+GQPiwVVf stGwSA1McfFJUttTgq2Huu74KARhtA8wPo/N3XcyYQtNhz+qCM5NBb3e cx/naw6sYab9LxS6f2cU0q03++BP5Ks0Uef8WJCa/1izCYE+vMkwoltV +tENa3hpXiZ7jle/xdgaZrPi5ZGmyLVI34g1XVYrNlsCCTmNvFQIfzW5 STFQFsQpizczyFn9r3LzSxxPCNwdlCG84bER0BmdwqbF6Tanv+FxMOav rahkj4wIy5k=
체인 전체를 시각적으로 확인하기
https://dnsviz.net/d/cloudflare.com/dnssec/
DNSViz는 롤오버 중인 키와 DS의 연결 관계를 그래프로 보여줍니다.
키가 여러 개일 때 어느 것이 어느 DS와 이어져 있는지 한눈에 파악할 수 있어, 롤오버 상태를 점검할 때 특히 유용합니다.
9. 참고 자료 (Reference Links)
- RFC 6781 - DNSSEC Operational Practices, Version 2
- RFC 7344 - Automating DNSSEC Delegation Trust Maintenance
- RFC 8078 - Managing DS Records from the Parent via CDS/CDNSKEY
- RFC 8624 - Algorithm Implementation Requirements for DNSSEC
- DNSViz - DNSSEC 체인 시각화 도구