イントロ
昨年末に Cloudflare で短期間に発生した二つの大規模障害は、一見すると個別の技術トラブルのように見えます。しかし実際には、いずれも「設計上の前提が崩れたとき、障害がどのように全体へ拡大するか」を示す象徴的な事例でした。
この記事では、次の3点を中心に整理します。
- Cloudflare の役割
- 11月18日および12月5日の障害概要
- そこから得られる設計・運用上の教訓
クラウド事業者とは何か
Cloudflare を位置づけるために、まずクラウド事業者の役割を簡単に整理します。
クラウド事業者とは、企業が個別に保有していたサーバーやネットワークなどの IT 基盤を、インターネット経由で提供する事業者です。その結果、自前でインフラを持たずとも迅速にシステムを利用できるようになりました。
代表例としては AWS、Azure、GCP などが挙げられます。
一方で、多くのシステムが共通基盤上で動作する集中化が進んでいます。この環境では変更が速く、影響範囲も広がりやすいため、単一の変更が多数の利用者に同時に波及し、問題発生時には影響範囲が急激に広がります。
クラウド事業者におけるCloudflareの位置づけ
AWS や GCP がサーバー基盤を提供するのに対し、Cloudflare はユーザーとオリジンサーバーの手前に位置するリバースプロキシ層です。
この層で Cloudflare は、CDN による配信最適化や WAF による不正な通信の遮断などを担っています。通信経路そのものを支える基盤のため、障害時には多数のサービスが同時に利用不能となり得ます。
上図は障害時のエラーページ例です。Browser と Host までは到達していますが、Cloudflare 側でエラーが発生していることが示されています。
11月18日 障害のタイムライン
以下、このタイムラインに沿って障害の状況を整理します。
11月18日の障害では、ChatGPT や X、Spotify など Cloudflare を経由する複数の主要サービスで、同時にアクセス障害が発生しました。
これらはいずれも大規模かつ日常的に利用されるサービスであり、影響の広がりは瞬時に顕在化しました。
利用者の感覚としては、特定サービスの問題というよりも、インターネット全体が不安定になったように見える状況でした。
これは Cloudflare が通信経路の中間層に位置しているという構造的特性によるものです。
影響は短時間では収束せず、11時30分頃から14時30分頃までの約3時間、幅広い範囲でエラーが継続しました。
特定リージョンに限定されず、複数地域にまたがって断続的なエラーが発生していました。
このような規模と同時多発性から、当初は外部攻撃の可能性も疑われました。
実際、Cloudflare 内部でも当初は外部要因を前提とした調査が進められていました。
大規模 DDoS 攻撃であれば、類似したトラフィックパターンが観測されるためです。
しかし、事後に整理されたタイムラインを見ると、11時05分の内部更新を起点に、20分以上かけて影響が段階的に広がっていました。
外部から一気に発生した障害ではありませんでした。
つまり、影響は瞬間的に発生したのではなく、内部変更が段階的に波及した結果でした。
ピーク時だけを見ると超大規模な DDoS 攻撃にも見えますが、実際は内部変更が時間をかけて波及したタイプの大規模障害でした。
この点から、今回の障害は「外部攻撃ではなく、内部変更が波及したもの」だったと言えます。
11月18日 障害の技術的背景
障害の概要
まず今回の障害の全体像を、構造の観点から整理します。
ここでは個別の技術要素というよりも、因果関係の流れに焦点を当てます。
今回の障害は、ClickHouse の権限変更をきっかけとして、Bot Management 用の設定が想定を超えた形で生成されたことから始まりました。
この時点ではまだ障害は顕在化しておらず、内部状態の変化が静かに進行している段階でした。
重要なのは、この設定自体が「壊れた設定」や「無効な設定」ではなく、システム上は有効な設定として扱われていた点です。
つまり、フォーマット上のエラーや明確な破損は存在していませんでした。
そのため、設定の生成や配布、同期といった個々の処理はすべて正常に動作し、誤った状態が主経路を通って全体に配布される形になりました。
ここで注目すべきなのは、「異常な値」が「正常処理」を経由して広がったという点です。
今回の障害は、単一のバグや誤作動によって一気に発生したものではなく、複数の正常な処理が連鎖することで、局所的な異常が全体障害へと拡大した、構造的な障害だったと言えます。
すなわち、各コンポーネント単体では正しく動作していたにもかかわらず、前提条件の崩れが連鎖し、結果として全体停止へと至りました。
技術的な原因
次に、技術的に何が起きていたのかを整理します。
ここでは、処理の流れを段階ごとに分解して見ていきます。
まず、ClickHouse に対する権限変更により、従来よりも広い範囲のメタデータが参照可能な状態になりました。
この権限変更自体は、分析や可視化の利便性向上を目的としたものであり、直接的な不具合ではありませんでした。
その結果、system.columns を用いたクエリが、想定していなかった別データベース上の同名テーブルの情報も取得するようになりました。
system.columns はメタデータ全体を横断的に参照できるため、参照範囲の拡張はクエリ結果の構造そのものに影響を与えました。
この影響で、Bot Management の feature file 生成処理では、同一構造の列情報が重複して取得され、feature 数が想定以上に増加する結果となりました。
つまり、ロジック上は正しいデータ取得であったものの、前提としていたデータ量を超過する状態が発生していました。
従来は約60個程度だった feature 数が、結果として200を超える状態になっています。
この増加は単なる数値的変化ではなく、下流処理の前提条件を破壊する水準に達していました。
一方で、Rust で実装された Bot Management の実行コードでは、性能を前提として、feature 数の上限が200に固定されていました。
この設計はメモリ使用量や評価コストを抑制するための合理的な制限であり、通常の運用条件では問題を生じることはありませんでした。
この上限は、通常の前提条件の下では十分に妥当な設計です。
すなわち、「feature 数は200を超えない」という暗黙の前提が存在していました。
そのため、想定を超えた feature file が入力された結果、各プロキシノード上で panic が発生する状態になりました。
panic は「想定外の状態」を検知して即座に止まる、防御的な挙動です。
何が問題だったのか
最後に、今回の障害で本当に問題だった点を整理します。
ここで重要なのは、個別の技術要素ではなく、設計思想そのものに目を向けることです。
ClickHouse の権限管理や、メタデータ参照範囲の拡張は、高速な分析処理を前提とした設計思想に基づくものであり、通常の前提条件の下では合理的な挙動です。
これは大規模データ基盤においては一般的な設計方針であり、性能最適化を優先する構造は珍しいものではありません。
system.columns のようなメタデータ取得においても、厳密な制約より実行効率が優先されています。
すなわち、「多少広く取得する代わりに高速に処理する」という思想が採用されています。
同様に、Rust による実装や feature 数の上限チェックも、通常の前提条件の下では合理的な設計でした。
200という上限値も、実運用上の観測データを前提とした妥当な設定でした。
Rust で発生した panic は、プログラムが壊れたわけではなく、「この状態は起きないはずだ」という前提が崩れたことを検知した結果です。
これは防御的設計の一種であり、想定外入力に対して即時停止する仕組みでした。
仮に panic が発生しなかったとしても、問題が解消されたとは限りません。
処理を継続していれば、誤った設定を使ったまま動作したり、性能劣化や検知精度の低下といった、より見えにくい形で問題が続いた可能性もあります。
つまり、panic は表面化のきっかけであって、本質的原因ではありません。
つまり、今回の障害の本質は特定の言語や実装ではなく、前提条件が崩れた際に、その異常を途中で検知し、局所的に遮断する仕組みが存在していなかった点にあります。
ここで言う「前提条件」とは、データ量の上限、オブジェクトの必存在、処理経路の安定性といった、暗黙の設計仮定を指します。
前提が崩れた瞬間に、それが無緩衝で全体に反映される。
この構造こそが、今回最も危険だった点です。
すなわち、異常を局所で止める“バッファ層”が存在しなかったことが、全体停止へと直結しました。
12月5日 障害のタイムライン
まず、12月の障害は11月の障害と性質がかなり違う点を確認しておきます。
この違いを明確にすることが、12月の障害構造を理解する前提です。
11月の障害は、内部変更を起点として、時間をかけて影響が拡大していくタイプでした。
つまり、内部状態の変化が徐々に波及し、最終的に広範囲へ影響が広がる構造でした。
一方で12月の障害は、影響の立ち上がりも、復旧も非常に速いという特徴があります。
障害の顕在化から復旧までの時間軸が短く、瞬間的にエラーが集中発生した点が特徴的でした。
そのため、11月のように「何時何分に何が起きたか」を細かく追う必要はなく、どのような流れで問題が表面化したのかを見る方が重要になります。
この障害では、時系列よりも「制御フローの変化」に注目することが重要です。
12月5日 障害の技術的背景
障害の概要
12月の障害は、突然発生したものではありません。
表面的には急激に顕在化しましたが、その背後では段階的な変更が進行していました。
12月3日から、React や Next.js に関するセキュリティ対応が進められており、それに対応して、Cloudflare 側では WAF を中心とした防御ルールの調整が段階的に行われていました。
これらの変更自体は、外部ライブラリ側の脆弱性対応に追随するためのものであり、通常であれば必要かつ妥当な対応でした。
しかし、それらの変更が本番環境に広く適用された結果、一部のリクエストが、普段はほとんど通らない処理経路を通るようになりました。
ここで重要なのは、コードが変更されたというよりも、「選択される実行経路」が変化した点です。
その経路上で、潜在していた問題が実際のトラフィックで初めて表面化し、障害として観測されることになります。
つまり、低頻度経路に存在していた前提条件の不備が、実トラフィック下で初めて顕在化した構造でした。
技術的な原因
背景として、Cloudflare の WAF は HTTP リクエストを検査する際に、プロキシ内部で保持しているリクエストボディのキャッシュを参照しています。
このキャッシュは、検査処理の効率性とメモリ消費のバランスを取るために設計されたものでした。
当時、このキャッシュの上限は 128KB でした。
通常のリクエストサイズを前提とすれば、この制限は十分に妥当な値でした。
React や Next.js の仕様変更に対応する中で、WAF が検査対象とすべきリクエストボディのサイズが大きくなり、このままでは十分な検査が行えない状況が発生しました。
すなわち、従来のキャッシュ上限では、完全なセキュリティ検査が保証できなくなりました。
そのため Cloudflare は、プロキシのキャッシュ上限を 128KB から 1MB に引き上げる変更を進めました。
この変更自体は、防御精度を維持するための合理的な対応でした。
ただし、この変更をリリースする過程で、WAF のテスト用ツールが 1MB のリクエストボディに対応していないことが分かりました。
ここで問題となったのは、本番処理の不具合ではなく、リリース工程上の制約でした。
つまり、コードの正しさではなく、検証経路の制限がボトルネックとなっていました。
そこで Cloudflare は、WAF 全体を無効化するのではなく、テストに関係する特定のルール分岐を一時的にスキップする対応を取りました。
これは影響範囲を限定しながらリリースを進めるための現実的な判断でした。
しかし、その後の Lua 評価処理は通常どおり実行されました。
ここで処理の整合性にズレが生じます。
この Lua 処理では、action が execute の場合には、対応する execute オブジェクトが必ず存在するという前提で処理が書かれていました。
つまり、「execute が null である」という状態は設計上想定されていませんでした。
ところが今回は、前段の分岐をスキップした影響で、本来生成されるはずだった execute オブジェクトが null のままとなっていました。
この時点で、前提条件が静かに崩れています。
その状態で Lua 処理が実行され、null となった execute のパラメータ results_index を参照したことで、nil dereference が発生しました。
これは言語特有の問題というよりも、前提崩壊に対する防御不足によるものでした。
この Lua コードは新しく追加されたものではなく、これまで前提条件が崩れなかったために問題にならなかった部分です。
つまり、潜在的な不整合が長期間存在していたことになります。
ただ今回は、その前提が破られ、潜在していた問題が顕在化しました。
低頻度経路であったため、通常の運用では表面化していませんでした。
さらに、この Lua 処理は FL1 と呼ばれる高頻度で実行されるプロキシ層で動いていたため、同じエラーが短時間に大量発生し、影響が一気に拡大しました。
すなわち、局所的な前提崩壊が高頻度層で発生したことにより、瞬時に全体障害へと拡大しました。
教訓
これまで説明してきた内容を踏まえて、今回の障害から得られる教訓を整理します。ここでは個々のバグではなく、設計と運用の構造的な側面に焦点を当てます。
コード設計における前提条件の崩壊
11月の障害では、設定ファイルのエントリ数が増加したことで、通常とは異なる処理経路が選択されました。つまり、データ規模の変化が制御フローを変化させました。
このとき、「取得されるデータ量には上限がある」という暗黙の前提が崩れましたが、その異常を検知して止める仕組みは存在していませんでした。上限チェックは存在していましたが、それは最終段階での停止機構であり、拡散を防ぐ設計ではありませんでした。
12月の障害でも同様に、コードは「普段通る経路」を前提として書かれており、低頻度でしか実行されない経路上で null dereference が直接発生しました。これは制御経路に対する暗黙前提の崩壊でした。
本来であれば異常系として処理されるべき状態が、そのまま実行時エラーとして顕在化した点が今回の特徴です。すなわち、異常を吸収する層が存在していませんでした。
運用設計と配信経路のリスク
次に、運用設計と設定管理の観点です。ここでは技術的実装ではなく、リリースプロセスに注目します。
12月5日の障害では、外部要因への迅速な対応が求められ、通常の検証手順や段階的なリリースを経ずに、即時性を優先したルール配信が行われました。これは緊急対応としては合理的な判断でした。
その結果、普通にはほとんど使用されていなかった非標準の配信経路が本番環境で選択される結果となりました。つまり、通常時には負荷検証されていない経路が実トラフィック下で使用されました。
この経路は、通常運用では十分なトラフィックを通過しておらず、実トラフィック下での振る舞いが完全には検証されていませんでした。低頻度経路はテストカバレッジから漏れやすいという構造的問題があります。
経路内に存在していた例外処理の不足が、本番環境で初めて顕在化した点が、今回の障害につながっています。これは技術的不具合というよりも、「運用と設計の接点」に潜んでいたリスクでした。
閑話休題:インターネットの集中構造
ここからは、少し視点を引いて、現代のインターネット全体の構造について雑談的に考えてみたいと思います。
これまでの障害事例を踏まえた上で、その背景にある構造そのものを見直してみます。
もともとインターネットは、特定の拠点が壊れても全体が生き残るような、分散型を前提として設計された仕組みでした。
これは軍事通信網に由来する設計思想であり、単一点障害を回避することが基本理念でした。
しかし現在のインターネットを見ると、その姿はかなり変わっています。
理論上の分散構造と、実際の運用構造との間には、無視できない差が生じています。
配信や防御の仕組みは、Cloudflare のような少数の事業者に集約されつつあります。
CDN や WAF の層は、一部の事業者(数社)への依存が大きい状況です。
一方で、アプリケーションやデータは、AWS や GCP といった限られたクラウドの上で動いています。
インフラレイヤーも同様に、集中化が進行しています。
結果として、ネットワーク基盤も、アプリケーション基盤も、現代のインターネットは少数の巨大なハブの上に成り立つ構造になりました。
この構造では、局所障害が瞬時に広域へ波及する可能性を常に内包しています。
ただ一方で、もしインターネットが設計当初の理論的な理想だけをそのまま守り続けていたら、今のような形で数十億人が日常的に依存する社会インフラになっていたかどうかは、正直なところ分かりません。
高度な可用性やセキュリティ、運用効率を同時に満たすには、大規模な集中基盤の存在が現実的な選択肢だったとも考えられます。
高い可用性や、高度な防御、運用の効率化といった要求に対して、結果として私たちは集中した基盤に依存する構造を選んできた、とも言えると思います。
それは偶然ではなく、効率と安全性を追求した結果でもあります。
皮肉ではありますが、同じ基盤に依存し、同じ障害の影響を受けるという状況は、ある意味で「人類運命共同体」のような構造とも言えるかもしれません。
分散を理想としながら、実態としては高度に結節化されたネットワークの上に社会が成立しているという点に、現代インターネットの構造的特徴が表れています。
まとめ
この記事の目的は、Cloudflare を評価や批判の対象とすることではなく、障害事例から設計と運用の教訓を整理することです。
今回取り上げた二つの障害は、いずれも非常に具体的であり、大規模な基盤を持つシステムなら、どこでも起こりうる現実的な事象でした。
設定の規模変化、普段は通らない処理経路、緊急時に選択される非標準の運用ルート。
これらは、クラウド規模の拡大に伴い、多くのシステムが直面する課題でもあります。
重要なのは、今回の障害を特殊な事例として切り離すのではなく、自らの設計や運用に置き換えて考えることです。
そうすることで初めて、このような事例は単なる障害報告ではなく、今後に向けた実践的な知見として活かすことができます。
参考資料
https://blog.cloudflare.com/ja-jp/18-november-2025-outage/
https://blog.cloudflare.com/ja-jp/5-december-2025-outage/



