本文へ移動

2026-07-01 時点の資料です。読みやすさのために、一部の文字の色を濃くしています。

Pipeline

スキャンの仕組み/ How Scanning Works

アップロードされたファイルが、どのように検査され、検査済みと隔離に振り分けられるか。まず処理の全体フローを、業務の意味と技術要素を併記した一枚の図で、下流の終点(アプリで閲覧可/管理画面で管理)まで示します。次に時系列のシーケンス図で追い、最後に検査結果の 3 分類と、検査完了後に動き出す下流の連携を説明します。

01

処理の全体フローEnd-to-End Flow

アップロード着地から検査・振り分け、そして下流の終点までを一枚で示します。各段には業務の意味と、それを担う技術要素を併記しています。検査済み(clean)はアプリで閲覧でき、感染(infected)は管理画面での管理・取り出しに回ります。

図 01 · 処理の全体フロー — 着地から検査・振り分け、下流の終点まで(業務 + 技術)
① アップロード着地未検査バケットへ finalize② 到着を検知Eventarc(OIDC Push で配送)③ 検査matsuba-scanner・clamd に INSTREAM④ 振り分け(clean / infected)clean(安全)infected(感染)検査済みバケットCloud Storage(GCS)アプリで閲覧可一覧・DL・プレビュー・共有・Drive同期PostgreSQL:scan_status=clean・RLS+ 下流連携(サムネ・同期・通知)隔離バケット + 隔離台帳Cloud Storage・quarantined_files管理画面で管理・取り出しmatsuba-web · /admin/quarantine+ 感染通知(file.scan_infected)

各段の上段が業務の意味、下段が技術要素です。検査済み(clean)と確定したものだけが「アプリで閲覧可」へ進み、未検査・検査中・感染・失敗は利用者から見えません(→隔離と管理)。下流連携(サムネイル生成・Drive 同期・通知)の内訳は、この下の「検査完了イベントと下流連携」で扱います。

検査は外部サービスに送らず、matsuba-scanner のコンテナ内に同居した clamd にファイルをストリーム(INSTREAM)で流し込みます(ディスクに丸ごと保存してから検査するのではなく、読みながら検査する方式)。到着の検知から状態更新まで、人手は介在しません。
02

処理シーケンス(時系列)Sequence

同じ流れを、誰が誰に何を渡すか、という時間順で追います。クライアントはファイルを matsuba-api ではなく未検査バケットへ直接アップロードする点(API はサーバ負荷を持たず署名付き URL を発行するだけ)に注目してください。

図 03 · シーケンス — アップロードからクリーン/隔離まで
ユーザmatsuba-apiアプリ本体未検査バケットEventarcmatsuba-scannerclamd で検査検査済み/隔離バケットPostgreSQL / Pub/Sub状態・イベント① アップロード要求② 署名付き URL を発行③ 未検査バケットへ直接 PUT④ 完了通知 → 状態を scanning に⑤ 到着イベント(finalize)⑥ Push(OIDC 検証)⑦ ストリーム読み取り⑧ clamd で INSTREAM 検査検査結果クリーン(OK)検査済みバケットへ移送(rewrite)scan_status=clean・現在版を前進file.scan_clean を publish感染(FOUND)隔離バケットへ移送(rewrite)台帳に記録・critical アラート起票file.scan_infected を publish下流(検査完了後)clean:下流連携(サムネ・同期・通知)が起動し、利用者に開放(一覧・DL・プレビュー・共有・Drive同期)infected:隔離台帳に記録し、管理画面で管理・取り出し。感染通知が管理者・アップロード者へ届く

最後の publish が「合図」になり、下流の処理(サムネイル生成・Drive 同期・通知)が動き出します(次の「検査後の『合図』と下流」)。クリーン確定時のみ、そのファイルの現在版が前に進み、利用者に開放されます。

03

検査結果の 3 分類Three Verdicts

検査は「安全/危険」の二択ではありません。ウイルスそのものに加えて、アプリで扱わない形式に偽装したファイルや、中身を検証できないファイルも、それぞれ別の扱いにします。

分類例検出のしかた扱い・利用者への表示
① マルウェアウイルス・トロイの木馬などの実検出clamd が検出(FOUND)隔離し、管理者へ critical 通知。利用者には「ウイルスを検出」
② 偽装・回避アプリで扱わない拡張子(マクロ付き文書など)/中身と拡張子の不一致matsuba-scanner が検査前に判定(拡張子・先頭バイト=マジックバイト)①と同じく隔離。利用者には「不正なファイル」
③ 検証不能パスワード付き(暗号化)の zip・文書/スキャン上限を超える巨大・複雑なファイルclamd のヒューリスティック(中身を開けない/上限到達)受信者へ渡さず止める(block)が、隔離もアラートもしない。利用者には「スキャンできません」+再アップロードの案内

③は攻撃ではなく、パスワード付き zip を送る商習慣(いわゆる PPAP)などで正規に発生します。中身を検証できない以上、安全とは言い切れないため受信者には渡しません。ただし危険と断定もできないため、①②のような赤い警告や管理者アラートとは分け、アップロードした本人に「パスワードを解除して、あるいは分割して、もう一度アップロードしてください」と穏やかに案内します。

図 04 · 判定の分岐 — 検査前の事前判定と、clamd の判定結果
ファイル事前判定拡張子・マジックバイトclamd で検査シグネチャ+ヒューリスティック① マルウェア → 隔離② 偽装 → 隔離③ 検証不能 → blockOK → クリーン(開放)通過偽装FOUND暗号化・上限OK

②の偽装は clamd に渡す前に matsuba-scanner 自身が弾きます(アプリで扱わない形式は、そもそもウイルス検査以前に受け付けない)。③の判定は clamd が返す名前の接頭辞(暗号化・上限)で見分けます。

04

検査完了イベントと下流連携Downstream

検査結果は、matsuba-scanner が Pub/Sub(サービス間でメッセージを配送する仕組み)に流します。この合図を受けて、後続の処理がそれぞれ独立に動きます。

合図(イベント)受け取る処理役割
file.scan_clean
検査済みになった
サムネイル生成(matsuba-thumbnailer)一覧用の小さな見本画像を作る
Drive 同期(matsuba-sync)共有ドライブへ反映する
アップロード通知Box のメンバーに「アップロード完了」を知らせる
file.scan_infected
感染を検出した
感染通知管理者・アップロード者・Box オーナーへ即時に知らせる(配信は通知基盤が担当)

重要なのは、検査を通過した合図が出て初めて、サムネイル生成や Drive 同期が動く点です。検査前・検査中のファイルは下流に一切流れません。また matsuba-scanner は合図を出すところまでが仕事で、その先(サムネイルを作る、メールを送る)は各処理の担当に委ねます。互いに切り離されているため、片方が止まってももう片方に影響しません。

05

重複配信への冪等対策Idempotency

イベント方式には「同じ通知が 2 回届くことがある(at-least-once)」という性質があります。二重に処理しないための備えです。

matsuba-scanner は、受け取ったファイルの現在の状態(未検査/検査中/検査済み/感染)を最初に確認します。すでに検査済み・感染と確定していれば、何もせず受領だけ返します(冪等=何回届いても結果は 1 回分)。イベントの識別子はファイルの版から決定的に決まるため、重複配信でも同じ識別子になり、下流でも取り違えません。

この設計により、通信の再送や一時的な失敗があっても、二重のサムネイル生成や二重の通知は起こりません。失敗したスキャンの扱い(再試行・再スキャン)は「隔離と管理」で説明します。