17P by GN⁺ 2일전 | ★ favorite | 댓글 8개
  • 2025년 11월 18일 11시 20분(UTC)에 Cloudflare 네트워크의 핵심 트래픽 전달 기능이 중단되어 전 세계 사용자들이 오류 페이지를 보게 됨
  • 원인은 데이터베이스 권한 변경으로 인해 Bot Management 시스템의 ‘feature 파일’이 비정상적으로 커진 것이며, 사이버 공격과는 무관함
  • 이 파일 크기 증가로 인해 트래픽 라우팅 소프트웨어가 한계치를 초과해 실패, HTTP 5xx 오류가 대규모로 발생
  • 14시 30분경 문제 파일의 배포를 중단하고 이전 정상 버전으로 교체해 핵심 트래픽 복구, 17시 6분에 모든 서비스 정상화
  • Cloudflare는 이번 사태를 2019년 이후 최악의 장애로 평가하며, 구성 파일 검증 강화와 전역 차단 스위치 도입 등 재발 방지 조치 추진

장애 개요

  • 11시 20분경 Cloudflare 네트워크에서 핵심 트래픽 전달 실패가 발생, 사용자들은 Cloudflare 내부 오류 페이지를 확인
  • 사이버 공격이나 악의적 행위는 원인이 아님, 데이터베이스 시스템의 권한 변경이 직접적 원인
  • 해당 변경으로 인해 Bot Management 시스템이 사용하는 ‘feature 파일’의 크기가 두 배로 증가, 네트워크 전반에 배포됨
  • 트래픽 라우팅 소프트웨어가 이 파일을 읽는 과정에서 파일 크기 제한을 초과, 시스템 오류 발생
  • 초기에는 대규모 DDoS 공격으로 오인했으나, 원인 파악 후 이전 정상 파일로 교체하여 복구 진행

장애 진행 및 영향

  • 11:20 이전에는 5xx 오류 비율이 정상 수준이었으나, 이후 잘못된 feature 파일 배포로 오류 급증
  • ClickHouse 데이터베이스 클러스터의 일부 노드에서 잘못된 쿼리 결과가 5분 간격으로 생성, 정상·비정상 파일이 번갈아 배포되어 시스템이 반복적으로 복구와 실패를 반복
  • 14:30부터 문제 파일 생성을 중단하고 정상 파일을 수동 삽입, 코어 프록시 재시작으로 복구
  • 17:06에 모든 서비스 정상화
서비스 영향 내용
Core CDN 및 보안 서비스 HTTP 5xx 오류 발생
Turnstile 로드 실패, 로그인 불가
Workers KV 게이트웨이 실패로 5xx 오류 급증
Dashboard Turnstile 장애로 로그인 불가
Email Security 스팸 탐지 정확도 일시 저하, 일부 자동 이동 실패
Access 인증 실패 다수 발생, 기존 세션은 유지
  • 장애 기간 동안 CDN 응답 지연 증가, 디버깅 시스템의 CPU 사용량 급증이 원인

장애 원인: Bot Management 시스템

  • Cloudflare의 Bot Management 모듈은 머신러닝 모델을 사용해 요청별 봇 점수를 생성
  • 모델 입력으로 사용되는 feature 구성 파일이 몇 분마다 네트워크 전체에 배포되어 최신 위협에 대응
  • ClickHouse 쿼리 동작 변경으로 중복된 feature 행이 다수 포함, 파일 크기 증가
  • 이로 인해 Bot Management 모듈이 오류를 일으켜 HTTP 5xx 응답 반환, Workers KV와 Access에도 영향
  • 신규 프록시 엔진 FL2에서는 5xx 오류 발생, 구버전 FL에서는 봇 점수가 0으로 설정되어 오탐 증가

ClickHouse 쿼리 동작 변경

  • 11:05에 ClickHouse의 데이터베이스 접근 권한 변경 배포
  • 기존에는 default 데이터베이스의 메타데이터만 조회 가능했으나, 변경 후 r0 데이터베이스의 메타데이터도 노출
  • Bot Management의 feature 파일 생성 쿼리가 데이터베이스 이름 필터 없이 실행, 결과적으로 중복 컬럼 반환
  • 이로 인해 feature 파일의 행 수가 두 배 이상 증가, 시스템 한계 초과

메모리 사전 할당 및 시스템 패닉

  • Bot Management 모듈은 최대 200개의 머신러닝 feature 제한을 두고 메모리를 사전 할당
  • 잘못된 파일이 200개를 초과하는 feature를 포함하면서 Rust 코드에서 panic 발생,
    thread fl2_worker_thread panicked: called Result::unwrap() on an Err value 오류 출력
  • 이로 인해 HTTP 5xx 오류 대량 발생

기타 영향 및 복구 과정

  • Workers KV와 Access가 코어 프록시에 의존해 장애 영향 확대
    • 13:04에 Workers KV가 프록시를 우회하도록 패치, 오류율 감소
  • Dashboard는 Turnstile과 Workers KV 의존으로 로그인 불가
    • 11:30~13:10, 14:40~15:30 두 차례 가용성 저하
    • 백로그와 재시도 요청으로 지연 증가, 15:30경 복구
  • 14:30 이후 대부분 서비스 정상화, 17:06 완전 복구

재발 방지 조치

  • Cloudflare 생성 구성 파일의 입력 검증 강화
  • 전역 기능 차단 스위치(kill switch) 확대
  • 오류 보고로 인한 시스템 자원 고갈 방지
  • 코어 프록시 모듈 전반의 오류 조건 검토

타임라인 요약 (UTC)

시각 상태 설명
11:05 정상 데이터베이스 접근 제어 변경 배포
11:28 영향 시작 고객 트래픽에서 첫 오류 발생
11:32–13:05 조사 진행 Workers KV 오류 원인 분석, 완화 시도
13:05 영향 감소 Workers KV 및 Access 우회 적용
13:37 복구 작업 집중 Bot Management 구성 파일 롤백 준비
14:24 문제 파일 배포 중단 정상 파일 테스트 완료
14:30 주요 영향 해소 정상 파일 전역 배포, 서비스 복구 시작
17:06 완전 복구 모든 서비스 정상화 완료

결론

  • 이번 장애는 Bot Management 구성 파일 생성 로직과 데이터베이스 권한 변경의 상호작용으로 발생
  • Cloudflare는 이를 2019년 이후 가장 심각한 네트워크 중단으로 평가
  • 향후 시스템 복원력 강화를 위한 구조적 개선과 자동화된 방어 체계 강화 추진

CF정도되는 회사에서도 .unwrap()을 쓰네요 ㄷㄷ
저 코드가 어떻게 프로덕션에 적용된거지

unwrap이 문제는 아닌거같은

근본적인 문제는 잘못된 쿼리죠.
근데 전 unwrap으로 문제 검증을 생략한 것도 문제라고 생각해요
내부적으로 문제가 생길지언정 에러처리했으면 트래픽 다운되진 않았을테니까요

설정파일 관련 장애는 어디서든 나네요.

Cloudflare가 안되어서 온갖 서비스가 중단되니 지옥이더군요..

원인분석 문서가 꽤 빠르게 공개됐네요ㄷㄷ

그나저나 이 글 작성자가 CEO 였네요

Hacker News 의견
  • 이건 수백만 달러짜리 .unwrap() 사고담
    인터넷의 핵심 인프라 경로에서 .unwrap()을 호출한다는 건 “절대 실패하지 않는다, 실패하면 바로 스레드를 죽인다”는 선언과 같음
    Rust 컴파일러는 실패 가능성을 명시적으로 표현하도록 강제하지만, 이들은 우아하게 처리하지 않고 패닉을 택했음
    전형적인 “parse, don’t validate” 안티패턴의 사례라고 생각함

    • 많은 사람들이 .unwrap()맹점이 있는 듯함. 예제 코드에서 자주 보이기 때문일지도 모름
      실제 운영 코드에서는 .unwrap()이나 .expect()를 패닉처럼 리뷰해야 함
      프로덕션 코드에서 .unwrap()을 쓴다면 반드시 “INFALLIBILITY” 주석을 달아야 하고, clippy::unwrap_used로 이를 강제할 수 있음
    • 이 글의 요점은 단일 원인보다 정상적인 구성요소들의 조합이 문제를 일으킨다는 것 같음
      단순히 .unwrap() 때문이 아니라, 쿼리가 데이터베이스를 구분하지 않아 페이로드가 커졌고, ClickHouse가 더 많은 DB를 노출했기 때문임
      “unwrap 때문”이라고 단정하기보다, 글로벌 킬 스위치나 시스템 리소스를 압도하지 않도록 하는 설계 개선이 더 중요하다고 봄
    • 사실 이건 Rust 경로 외에서도 실패했음. 봇 관리 시스템이 모든 트래픽을 봇으로 분류했기 때문임
      FL2 레이어에서 각 컴포넌트의 패닉을 잡아야 하지만, fail-open이 항상 더 나은 건 아님
      패닉을 잡아 처리할지 여부를 FL2 레벨에서 명시적으로 결정하도록 로직을 추가해야 함
    • 만약 우아하게 처리했다면 성능 저하가 있었을 것 같음 (그래도 신뢰성 저하보단 낫다고 생각함)
      샤딩된 시스템이라면 점진적 롤아웃과 모니터링이 왜 없었는지도 궁금함
    • Swift에는 암시적 ! 언랩과 명시적 ? 언랩이 있음
      나는 암시적 언랩을 거의 쓰지 않음. 보장된 값이라도 항상 명시적으로 처리함
      예를 들어 @IBOutlet weak var someView! 대신 @IBOutlet weak var someView?로 정의함
      일종의 belt & suspenders 접근임
  • 장애 후 24시간도 안 돼 post mortem을 공개한 건 정말 대단한 일임

    • 이렇게 빠르고 투명하게 공개할 수 있는 내부 정책이 궁금함
      대부분의 대기업이라면 여러 stakeholder 검토로 인해 코드 공개는 거의 불가능함
    • 게다가 글 자체도 잘 썼음. AWS의 포스트모템과 비교하면 거의 문학 수준임
  • Cloudflare의 장애 설명을 읽으며, “왜 복구에 그렇게 오래 걸렸을까” 궁금했음
    장애 원인은 이해했지만, 네트워크 대부분이 다운됐다면 최근 설정 변경을 되돌리는 게 1순위 아닌가 싶었음
    물론 사후적으로는 명확하지만, 7분 만에 조사 시작한 건 인상적임

    • 처음엔 공격으로 오인했음. 이후 문제를 파악했지만, 손상된 파일을 큐에 교체할 방법이 없었고, 전 세계 수많은 머신을 재시작해야 했음
  • 이 사건은 CrowdStrike 사고와 유사하게 느껴짐
    자동 생성된 설정 파일이 소프트웨어를 망가뜨렸고, 전체 네트워크로 전파됨
    빠른 배포가 필요하다는 건 이해하지만, 이번 일은 점진적 롤아웃과 롤백 전략의 부재를 드러냄

    • 이건 CI/CD 배포라기보다 분산 봇 탐지 시스템의 제어 채널로 보는 게 맞음
    • 시뮬레이터 없이 바로 프로덕션에 푸시했다는 게 놀라움
    • 그래도 이번 일을 계기로 개선이 이뤄질 거라 믿음
  • Cloudflare가 발표한 향후 개선 계획을 보면,

    • Cloudflare 생성 설정 파일의 검증 강화
    • 글로벌 킬 스위치 추가
    • 코어 덤프나 에러 리포트로 인한 리소스 고갈 방지
    • 프록시 모듈의 오류 모드 검토
      등이 있음
      하지만 카나리 배포나 점진적 구성 배포는 빠져 있음
      글로벌 스위치는 위험할 수 있고, 버그 하나로 전체 시스템을 멈출 수도 있음
    • 봇 관리 설정은 빠르게 전파돼야 하지만, 한 인스턴스에서 먼저 테스트했다면 패닉을 미리 잡았을 것임
      왜 ClickHouse를 feature flag 저장소로 썼는지도 의문임. ClickHouse deduplication 문서에도 위험 요소가 있음
    • 설정 서비스는 점진적 롤아웃이 있었지만, 소비하는 서비스들이 너무 자주 자동 업데이트되어 작은 비율의 오류도 전체에 영향을 줬음
    • 글로벌 설정은 빠른 대응에 유용하지만, 빠른 롤백 체계가 필수임
      서비스 간 의존 관계 맵핑이 있으면 원인 추적이 훨씬 쉬워질 것임
    • 결국 대부분의 대형 장애는 config push 때문임
      코드 배포는 신중하지만 설정 배포는 그렇지 않음. 설정도 코드라는 인식이 필요함
  • 상태 페이지가 다운돼 공격으로 오인했다는 부분이 흥미로움
    Cloudflare 인프라와 완전히 분리돼 있다는데, 왜 같이 죽었는지 설명이 없음

    • 아마 트래픽 급증으로 인한 인프라 확장 실패일 가능성이 높음
    • 실제로는 Cloudflare 의존성이 없다고 생각했지만, 인터넷의 상당 부분이 CloudFront에 의존하기 때문에 완전히 독립적이지 않았을 수도 있음
    • 원인을 알려면 statuspage.io의 포스트모템이 필요함. Atlassian이 운영하는 서비스임
    • 단순히 Cloudflare의 규모가 너무 커서 트래픽이 몰렸을 수도 있음
  • 나는 Turnstile을 fail-open 전략으로 통합했는데, 이번 장애에서 효과를 봤음
    JS가 로드되지 않으면 더미 토큰으로 제출을 허용하고, 백엔드에서 검증 실패 시에도 fail-open으로 처리함
    일부 사용자는 여전히 차단됐지만, 전체 영향은 줄었음
    다른 봇 완화 수단이 있어서 가능한 접근임

    • 그렇다면 공격자가 스크립트를 차단하면 CAPTCHA를 우회할 수 있지 않냐는 의문이 있음
      하지만 이는 타깃형 공격이 아닐 때만 통할 것 같음
  • 왜 Cloudflare 코드에 .unwrap()을 허용했는지 의문임
    최소한 expect("이건 절대 일어나지 않음")이라도 써야 했음
    에러를 값으로 다루는 철학이 이런 문제를 막기 위한 것인데, 진단을 훨씬 쉽게 했을 것임

    • 나는 Cloudflare 직원은 아니지만 Rust를 많이 씀
      네트워크 호출이 포함된 코드에서는 실패 가능성이 너무 많음
      개발 중엔 .unwrap()을 쓰지만, 프로덕션에서는 종종 expect() 를 남겨두기도 함. 더 이상 진행할 방법이 없을 때가 있기 때문임
  • 진짜 교훈은 너무 많은 기능이 소수의 플레이어에 의존한다는 점임
    승자독식 구조가 심화되며 시스템의 탄력성이 떨어지고 있음
    물론 그들이 실력으로 얻은 자리지만, 인터넷이 항상 “정상 작동”할 거라 기대하는 건 과한 것 같음

  • “Rust면 다 안전하다”는 말은 과장임
    어떤 언어든 잘못 쓰면 총구를 자기 발에 겨누는 것과 같음