# Cloudflare 2025년 11월 18일 장애 사후 분석

> Clean Markdown view of GeekNews topic #24471. Use the original source for factual precision when an external source URL is present.

## Metadata

- GeekNews HTML: [https://news.hada.io/topic?id=24471](https://news.hada.io/topic?id=24471)
- GeekNews Markdown: [https://news.hada.io/topic/24471.md](https://news.hada.io/topic/24471.md)
- Type: GN+
- Author: [neo](https://news.hada.io/@neo)
- Published: 2025-11-19T11:33:30+09:00
- Updated: 2025-11-19T11:33:30+09:00
- Original source: [blog.cloudflare.com](https://blog.cloudflare.com/18-november-2025-outage/)
- Points: 23
- Comments: 8

## Summary

Cloudflare가 2025년 11월 18일 겪은 대규모 장애는 **Bot Management 시스템의 구성 파일(feature 파일)** 이 비정상적으로 커지면서 **트래픽 라우팅 소프트웨어가 한계치를 초과**해 전 세계 서비스가 중단된 사건이었습니다. 단순한 코드 버그가 아니라 **데이터베이스 권한 변경과 자동화된 구성 배포의 상호작용**이 만든 복합적 실패로, 글로벌 인프라에서도 작은 설정 변화가 얼마나 큰 파급력을 가질 수 있는지 보여줍니다. Cloudflare는 이후 **구성 검증 강화와 전역 차단 스위치 도입** 등 재발 방지책을 추진 중이며, 이는 대규모 분산 시스템 운영자들에게 “자동화는 강력하지만, 검증 없는 자동화는 위험하다”는 교훈을 다시 상기시킵니다.

## Topic Body

- 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년 이후 가장 심각한 네트워크 중단**으로 평가  
- 향후 시스템 복원력 강화를 위한 구조적 개선과 자동화된 방어 체계 강화 추진

## Comments



### Comment 46567

- Author: t7vonn
- Created: 2025-11-19T23:58:22+09:00
- Points: 1

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

### Comment 46553

- Author: princox
- Created: 2025-11-19T15:17:58+09:00
- Points: 1

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

### Comment 46550

- Author: epdlemflaj
- Created: 2025-11-19T14:56:47+09:00
- Points: 1

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

### Comment 46557

- Author: epdlemflaj
- Created: 2025-11-19T15:39:53+09:00
- Points: 3
- Parent comment: 46550
- Depth: 1

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

### Comment 46536

- Author: neo
- Created: 2025-11-19T11:33:31+09:00
- Points: 1

###### [Hacker News 의견](https://news.ycombinator.com/item?id=45973709) 
- 이건 수백만 달러짜리 **.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 문서](https://clickhouse.com/docs/guides/developer/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면 다 안전하다”는 말은 과장임  
  어떤 언어든 **잘못 쓰면 총구를 자기 발에 겨누는 것**과 같음

### Comment 46551

- Author: barca105
- Created: 2025-11-19T15:03:31+09:00
- Points: 2

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

### Comment 46559

- Author: skageektp
- Created: 2025-11-19T15:53:00+09:00
- Points: 2
- Parent comment: 46551
- Depth: 1

unwrap이 문제는 아닌거같은

### Comment 46561

- Author: barca105
- Created: 2025-11-19T16:14:46+09:00
- Points: 2
- Parent comment: 46559
- Depth: 2

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