スペンサー・ジョンソンの『チーズはどこへ消えた?』は、周囲の変化にどう適応するかという話でした。クラウドセキュリティコンプライアンスの世界では、チーズ(設定画面)が常に動いています。Microsoftがメニュー名を変えた。Googleがトグルを別の管理パネルに移動した。丁寧に書いた実装ガイドが、もう存在しない画面を指している。お客様が古い手順に従って行き詰まる。
この問題を解決するため、ベンダードキュメントを毎週自動クロールし、自社ガイドとの差分を検出するパイプラインを構築しました。Cloudflare WorkersのDurable Workflowで稼働し、Claudeによるセマンティック分析でUIパス変更・機能廃止・設定移動を検知します。120ソース規模でも週あたり約50セントで運用可能です。
ドキュメントドリフトとは
イソリアでは、ISMSやCISコントロールに基づくセキュリティ管理策の実装ガイドを管理しています。「Microsoft Entraで管理者アカウントのMFAを有効にする」「条件付きアクセスポリシーを設定する」といった、画面操作レベルの具体的な手順書です。
クラウドベンダーはプラットフォームを頻繁に更新します。Entra ID(旧Azure AD)だけでも月に数回の変更があります。機能名の変更や管理画面の再編により、ガイドの記載内容が実際の画面と食い違う。これをドキュメントドリフトと呼んでいます。
従来、このドリフトの検知は完全に手動でした。コンサルタントがお客様先で差異に気づき、報告を上げ、誰かがガイドを修正する。フィードバックループが遅く、常に後手に回っていました。
3段ゲートパイプライン
コストを抑え、誤検知を減らし、完全自動で動く仕組みが必要でした。設計したのは、段階的にフィルタリングする3段ゲートのパイプラインです。各ゲートが不要な処理を除外してから、次のより高コストな処理に進みます。
%%{init: {'flowchart': {'nodeSpacing': 25, 'rankSpacing': 40, 'padding': 6}}}%%
flowchart TD
A["Cronトリガー<br/>毎週月曜 6:00 JST"] --> B["アクティブな<br/>ドキュメントソース読込"]
B --> C{"Gate 1<br/>RSSチェック"}
C -->|変更なし| Skip1["スキップ -- コスト節約"]
C -->|変更の可能性あり| D["ベンダードキュメント<br/>クロール"]
D --> E{"Gate 2<br/>コンテンツハッシュ"}
E -->|ハッシュ一致| Skip2["スキップ -- 実質変更なし"]
E -->|ハッシュ不一致| F{"Gate 3<br/>AI差分分析"}
F -->|意味のあるドリフトなし| G["現行版として記録"]
F -->|ドリフト検出| H["レビュー対象としてフラグ"]
style Skip1 fill:#d1fae5,stroke:#059669
style Skip2 fill:#d1fae5,stroke:#059669
style G fill:#dbeafe,stroke:#2563eb
style H fill:#fef3c7,stroke:#d97706
Gate 1: RSSチェック(無料・ミリ秒)
Microsoft Learnにはページ更新日を返すRSSエンドポイントがあります。クロール前にまずこれを確認し、前回チェック以降に更新がなければ、そのソースを丸ごとスキップします。通常の週では、大半のソースがこのゲートで除外されます。
Gate 2: コンテンツハッシュ(低コスト・秒単位)
RSSで変更の兆候があった場合、ベンダーページをクロールしてMarkdownのSHA-256ハッシュを算出します。前回保存したハッシュと一致すれば、実質的な内容変更はなかったと判断してスキップ。RSS日付が編集上の理由で更新されたケースや、体裁のみの変更をここで除外します。
Gate 3: AI差分分析(APIコスト・秒単位)
コンテンツが実際に変わった場合のみ、Claudeによるセマンティック比較を実行します。単純なテキスト差分ではなく、以下のカテゴリを検知対象にしています:
- UIパス変更: 「設定 > セキュリティ」が「保護 > 認証」に変わった
- 機能の廃止: ガイドで参照している機能が存在しなくなった
- 手順の並び替え: 設定手順の順序がベンダー側で変更された
- 新しい前提条件: 以前は不要だったステップが追加された
- 設定の移動: トグルが別の管理パネルに移された
軽微な文言変更、書式の違い、既存手順に影響しない新機能の追加は意図的に無視します。
アーキテクチャ: コンパニオンWorker
メインアプリケーションはSvelteKitで構築されており、CloudflareのアダプターはWorkflowクラスやscheduledハンドラーをサポートしていません。そこで、クローラーは別のWorkerとして稼働させ、同じD1データベースを共有する設計にしました。
%%{init: {'flowchart': {'nodeSpacing': 25, 'rankSpacing': 35, 'padding': 6}}}%%
flowchart LR
subgraph Main["Pulse (SvelteKit)"]
direction TB
API1["/api/doc-freshness/status"]
API2["/api/doc-freshness/review"]
end
subgraph Companion["Doc Freshness Worker"]
direction TB
Cron["Cronトリガー"] --> WF["Durable Workflow"]
Manual["POST /run"] --> WF
end
DB[("D1 Central")]
Main <--> DB
Companion <--> DB
Cloudflare Workflowsの耐久性(Durable Steps)を活用し、各ドキュメントソースごとに名前付きステップを割り当てています。クロールジョブが途中で失敗しても、最後に完了したステップから再開します。非同期クロールジョブの待機にはDurable Sleepを使い、CPU時間をゼロに抑えています。
/crawl APIの不安定さへの対処
Cloudflare Browser Renderingの/crawlエンドポイントは非同期で、時折原因不明のエラーを即座に返すことがあります。対策として:
- 3回のリトライ(20秒間隔のバックオフ付き)
- ソース間15秒のスタガー(レートリミット回避)
- Durable Sleepによるポーリング(CPU消費ゼロで待機)
これにより成功率を約50%から約90%に改善しました。残りの失敗は一過性で、翌週の実行で解消されます。
実際に検出したドリフト
これまでに検出した実例:
- Microsoftがユーザー単位MFAを非推奨とし、条件付きアクセスへの移行を推奨
- Entra管理センターのUIパスが再編成された
- レガシー認証ブロックの猶予期間が撤廃された
いずれも、お客様対応中に発覚していれば対応コストが発生するケースでした。ベンダー変更から1週間以内に検知できたことで、先手を打ってガイドを更新できています。
コスト
現在の10ドキュメントソース(M365の5コントロール × 英日2言語)では、週次コストはほぼゼロです。120ソース規模に拡大した場合の見積り:
| コンポーネント | 週次コスト |
|---|---|
| RSSチェック(Gate 1) | 無料 |
| Browser Renderingクロール | 約$0.30 |
| Claude AI分析(Gate 3) | 約$0.15 |
| Workerコンピュート + D1ストレージ | 無料枠内 |
| 合計(約120ソース) | 約$0.50 |
Gate 1とGate 2が高コストなAI呼び出しの大半を除外するため、ソース数が増えてもコストは線形には増加しません。
今後の展開
現在はMicrosoft 365のID管理コントロールのみを対象にしていますが、パイプラインはベンダー非依存で設計されています。新しいドキュメントソースの追加は、データベースにURLとクロール設定を1行追加するだけです。
- 対象拡大: 残りのM365コントロール、Google Workspace、Cloudflareドキュメント
- レビューUI構築: スタッフが差分を確認し、ガイド更新を承認・管理する画面
- ベンダー別Gate 1アダプター: GoogleやCloudflareはMicrosoftとは異なる変更通知の仕組みを持つため、個別対応が必要
- ガイド自動更新提案: ドリフトのフラグだけでなく、具体的な修正テキストをAIが提案
この仕組みが解決すること
セキュリティコンプライアンスガイドを運用している組織にとって、ドキュメントドリフトは見落としやすいリスクです。手動での検知は常に後手に回ります。
段階的にフィルタリングするパイプラインを組めば、コストも誤検知も低く抑えられます。Cloudflare WorkersのWorkflow機能(耐久性のあるステップ実行)とBrowser Rendering(ヘッドレスクロール)が、この種の定期的・非同期的な検査作業に適していました。
週1回の実行、わずかなコスト、実際のドリフト検出。コンサルタントの工数を削減する仕組みとして、十分に機能しています。

Comments
Nothing yet. Say the first thing.
Sign in to join the conversation.