ウイルス検査の連携Scanning
社外の取引先がファイルをアップロードする以上、ウイルス混入のリスクは避けられません。松葉は、アップロードされたファイルを、検査が終わるまで利用者の目に触れさせない仕組みを実装しました。鍵になるのは、ストレージへのファイル到着を「合図」にして検査サービスを自動起動する連携(Eventarc。イベント連携の仕組み)と、検査結果に応じた保管場所(バケット)の振り分けです。
到着を合図に、検査して振り分けるArrive, scan, sort
利用者がアップロードしたファイルは、まず「未検査」の保管場所に入ります。その到着を Eventarc が検知して検査サービスを起こし、検査結果に応じて「検査済み」か「隔離」へ移します。検査が済むまで、ファイルは利用者からは見えません。
状態の見える化: ファイルは「検査待ち」「検査中」「検査済み(問題なし)」「感染」といった状態を持ち、検査済みになって初めて利用者に提供されます。検査サービスは、検査が終わると保管場所を移し(未検査 → 検査済み、または隔離)、データベースの状態を更新し、結果をイベントとして知らせます。
役割で分けた 5 つの保管場所Five buckets
ストレージ(Cloud Storage)のバケット(保管場所)を、役割ごとに 5 つに物理的に分けています。検査前・検査済み・隔離を別々の場所に分けることで、「うっかり感染ファイルを取り出す経路」をそもそも作りません。
| 保管場所(バケット) | 役割 |
|---|---|
未検査バケット | アップロード直後の未検査ファイル(利用者には見えない) |
検査済みバケット | 検査済みで問題なし。利用者がダウンロードできる |
隔離バケット | 感染を検出して隔離。専用権限でしか取り出せない |
ミラーバケット(ウイルス定義) | 検査エンジンのウイルス定義ファイルの保管(今後使用) |
共有 ZIP バケット | 共有リンク用にまとめた ZIP の一時置き場 |
なぜ場所を分けるのか: 「未検査・検査済み・隔離」を 1 つの場所で状態フラグだけで区別すると、フラグの付け間違い 1 つで感染ファイルが利用可能になりかねません。物理的に別の場所に分け、業務 API には隔離バケットへのアクセス権限を一切与えないことで、設計の段階で危険な経路を断っています。最小権限(必要な権限だけを与える)の考え方を、検査の連携でも徹底しています。
取りこぼさない検査結果の発行Direct & idempotent
検査結果のイベントは、他の業務処理が使う発信箱(Outbox)を経由せず、検査サービスが直接発行します。これは手抜きではなく、検査の連携が持つ性質に合わせた意図的な設計です。
なぜ直接発行でよいのか: 検査の処理は、Eventarc が「届くまで何度でも再配信してくれる」仕組みの上で動きます。そのため、途中で失敗しても自動で再実行されるので、発信箱に溜めて後追いで送る必要がありません。あわせて、検査結果のイベントにはファイルの版から計算した決まった IDを付けます。同じファイルが再配信で 2 回検査されても、同じ ID になるため、受け取り側が「これは処理済み」と判定して二重処理を防げます(受け取り側の仕組みは「イベント駆動の整合性」へ)。
正直な注記: 現時点の検査サービスは、検査エンジン(ClamAV)をまだ接続しておらず、常に「問題なし」と判定する仮の検査で動いています。ただし、その前後(到着の検知・保管場所の振り分け・DB 更新・結果の発行)は本番と同じ作りです。今後の開発では、この仮の検査を実際の検査エンジンに差し替えて本稼働へ進めます。図で検査エンジンを破線にしているのは、この「あとは中身を差し込むだけ」という状態を表しています。