CNAME이 먼저인가, A 레코드가 먼저인가

7 hours ago 2

  • 2026년 1월 8일, Cloudflare의 1.1.1.1 서비스 업데이트가 DNS 응답 내 레코드 순서를 바꾸면서 전 세계 일부 사용자에게 DNS 해석 실패가 발생
  • 문제의 원인은 CNAME 레코드가 A/AAAA 레코드 뒤로 이동한 코드 변경으로, 일부 DNS 클라이언트 구현이 순서 의존적이었기 때문
  • 특히 glibc의 getaddrinfo 함수Cisco 스위치의 DNSC 프로세스가 영향을 받아, 후자의 경우 재부팅 루프까지 발생
  • RFC 1034는 “CNAME이 앞에 올 수 있다(possibly preface)”고만 명시해, 레코드 순서에 대한 명확한 표준이 부재
  • Cloudflare는 CNAME을 항상 먼저 배치하는 방식으로 복귀하고, IETF에 명확한 표준 정의를 위한 Internet-Draft를 제출

1. 사건 개요

  • 2026년 1월 8일, 1.1.1.1의 메모리 사용량 절감 업데이트가 배포되면서 DNS 응답 내 레코드 순서 변경이 발생
    • 변경은 2025년 12월 2일 코드베이스에 도입, 12월 10일 테스트 환경 배포, 2026년 1월 7일 글로벌 릴리스 시작
    • 1월 8일 18:19 UTC에 사고 선언, 18:27에 롤백 시작, 19:55에 복구 완료
  • 대부분의 현대 DNS 클라이언트는 응답 내 레코드 순서를 무시하지만, 일부 구현은 CNAME이 항상 먼저 와야 한다고 가정
  • 이 순서가 바뀌자 일부 클라이언트가 응답을 비어 있는 것으로 처리하며 해석 실패 발생

2. CNAME 체인과 캐시 동작

  • 도메인 질의 시, 예를 들어 www.example.com은 여러 CNAME 체인을 거쳐 최종 IP로 해석됨
    • 예: www.example.com → cdn.example.com → server.cdn-provider.com → 198.51.100.1
  • 각 CNAME 링크는 TTL(Time-To-Live) 을 가지며, 일부만 만료될 수 있음
  • 1.1.1.1은 만료된 부분만 재조회하고, 기존 캐시와 새 레코드를 병합하여 응답 구성

3. 코드 변경의 세부 내용

  • 기존 코드에서는 CNAME 체인을 먼저 삽입하고, 그 뒤에 A/AAAA 레코드를 추가
    • answer_rrs.extend_from_slice(&self.records); // CNAMEs first
  • 변경된 코드에서는 CNAME을 마지막에 추가
    • entry.answer.extend(self.records); // CNAMEs last
  • 이로 인해 응답 내에서 CNAME이 하단으로 이동, 일부 클라이언트가 이를 처리하지 못함

4. 영향을 받은 구현 사례

  • glibc의 getaddrinfo 함수는 응답을 순차적으로 파싱하며, CNAME이 먼저 등장해야 다음 이름을 추적 가능
    • CNAME이 뒤에 오면 “예상 이름”이 갱신되지 않아 결과가 비어 있음
  • Cisco Catalyst 스위치 3개 모델DNSC 프로세스도 영향을 받아, 1.1.1.1을 사용 중인 경우 치명적 오류로 재부팅 루프 발생
    • Cisco는 관련 서비스 문서를 공개

5. 영향을 받지 않은 구현

  • systemd-resolved는 응답을 OrderedSet 구조체로 파싱해, CNAME 위치와 관계없이 전체 집합을 탐색 가능
    • 따라서 레코드 순서 변경에도 정상 동작

6. RFC 1034의 모호성

  • RFC 1034(1987)은 “응답은 하나 이상의 CNAME으로 preface될 수 있다”고 기술
    • 그러나 MUST/SHOULD 같은 규범적 키워드가 없어 명시적 요구사항이 아님
  • RFC 2119(1997) 이후에야 이러한 키워드가 표준화되어, 당시 문서는 명확한 의무 표현이 부재
  • Cloudflare는 초기 구현에서 CNAME을 먼저 배치했으나, 테스트로 이를 보장하지는 않음

7. RRset과 메시지 섹션의 구분

  • RFC 1034 §3.6은 RRset(동일 이름·타입·클래스의 레코드 집합) 의 순서는 중요하지 않다고 명시
  • 그러나 서로 다른 RRset 간의 순서에 대해서는 언급이 없음
  • §6.2.1의 예시도 동일 이름의 A 레코드 두 개만 다루며, CNAME과 A의 상대적 순서는 다루지 않음
  • 따라서 CNAME과 A 레코드 간 순서 정의가 공백 상태

8. CNAME 체인 내부 순서 문제

  • CNAME이 여러 단계일 경우, 체인 자체의 순서가 뒤섞여도 순차 파싱이 실패
    • 예: cdn.example.com CNAME server.cdn-provider.com이 먼저 오면, www.example.com CNAME cdn.example.com을 찾지 못함
  • RFC 1034은 CNAME 체인 순서에 대한 요구사항도 없음

9. 리졸버의 동작 기준

  • RFC 1034 §5.2.2는 “리졸버는 CNAME을 만나면 새 이름으로 쿼리를 재시작해야 한다”고 명시
  • 그러나 이는 전체 리졸버(예: 1.1.1.1) 를 대상으로 한 설명이며,
    glibc 같은 스텁 리졸버는 이 로직을 구현하지 않음
  • 결과적으로 일부 스텁 리졸버가 RFC의 기대 동작을 따르지 않음

10. DNSSEC의 명시적 규정과 비교

  • RFC 4035(DNSSEC)는 RRSIG 레코드 포함 우선순위를 “MUST”로 명시
    • 단, 이는 “포함 여부”에 대한 규정이지 “순서”에 대한 것은 아님
  • DNSSEC은 명확한 포함 규칙을 제공하지만, 비서명 영역(Unsigned zones) 에서는 여전히 RFC 1034의 모호성이 남음

11. Cloudflare의 결론과 조치

  • RFC상 CNAME 순서가 필수는 아니지만, 일부 클라이언트가 이를 전제하므로
    CNAME을 항상 먼저 배치하는 정책으로 복귀
  • 향후 동일 문제 방지를 위해 IETF에 Internet-Draft 제출
  • Cloudflare는 이 사건을 통해 40년 된 프로토콜의 모호성이 여전히 실무에 영향을 미침을 확인

12. 부가 정보

  • Cloudflare는 1.1.1.1을 포함한 Connectivity Cloud를 통해
    기업 네트워크 보호, 인터넷 규모 애플리케이션 가속, DDoS 방어, Zero Trust 구현 지원을 제공
  • 무료 앱 1.1.1.1을 통해 더 빠르고 안전한 인터넷 접속 가능

Read Entire Article