Cloud Storage バケット 5 種Five-bucket storage
松葉のファイル保管基盤を、役割別に 5 バケットに分離しました。「アップロード直後の未スキャン → ウイルス検査 → クリーンに昇格、感染なら隔離」というウイルススキャン経路を、バケット境界とサービスアカウントの権限で表現しています。
全バケット共通でパブリックアクセス完全禁止、Uniform Bucket-Level Access(権限を細かいファイル単位ではなくバケット単位で管理する方式)、東京リージョン固定です。
5 種類のバケットFive buckets
バケット名はグローバルに一意である必要があるため、プロジェクト ID 末尾の <suffix> をサフィックスとして全バケットに付けています。
| バケット | 用途 | 自動削除(Lifecycle) |
|---|---|---|
未検査バケット | クライアントからの直接アップロードの宛先 | 一定期間経過で自動削除(保険) |
検査済みバケット | スキャン済み、利用者がダウンロード可 | Object Versioning ON(過去版を一定数保持・一定期間で自動削除) |
隔離バケット | 感染検出、隔離 | Object Versioning ON(推奨ルール OFF、誤削除復元のため) |
ミラーバケット | ClamAV(オープンソースのアンチウイルス)のシグネチャ定義 DB ミラー | なし(毎回上書き) |
共有 ZIP バケット | 共有リンクでまとめてダウンロードする時の一時 ZIP | 72 時間で自動削除 |
ウイルススキャン経路Upload → scan → clean / quarantine
5 段階の経路: ①利用者がブラウザから署名 URL(短命のアップロード許可証)を使って未検査バケットに直接アップロード → ②未検査バケットの変更を Eventarc が検知して matsuba-scanner に通知 → ③scanner が ClamAV で検査 → ④clean(問題なし)なら検査済みバケットに rewrite(コピー)、感染なら隔離バケットに rewrite → ⑤未検査バケット側を削除。バケット間を 「移動」ではなく「rewrite + 削除」とすることで、SA の権限が混ざらない設計です。
SA × バケットの権限マトリクスSA × bucket matrix
各バケットに対して、必要な SA に必要なロールだけを付与しています。「api の実行 SA(業務 API)は隔離バケットに触れない」のように、誤動作・脆弱性で隔離ファイルが復活する経路を構造的に排除しました。
| バケット | SA · ロール |
|---|---|
未検査バケット | api の実行 SA → Object Creator(署名 URL 発行)/ scanner の実行 SA → Object Admin(rewrite + 削除) |
検査済みバケット | api の実行 SA → Object Admin(DL 署名 URL + 世代管理)/ scanner の実行 SA → Object Admin(rewrite)/ sync の実行 SA → Object Viewer(Drive 同期) |
隔離バケット | scanner の実行 SA → Object Admin / 隔離読取専用 SA → Object Viewer / api の実行 SA → 付与しない |
ミラーバケット | scanner の実行 SA → Object Admin(freshclam R/W) |
共有 ZIP バケット | batch(Jobs)の実行 SA → Object Creator(ZIP 生成)/ api の実行 SA → Object Viewer(Signed URL 発行) |
api の実行 SA が隔離バケットに「無権限」である意図: 業務 API は社外取引先からのリクエストを直接受ける広い面を持っています。攻撃や脆弱性でこの SA が悪用されても、隔離されたファイルへの読み書き経路がそもそも存在しないため、感染ファイルが復元される攻撃シナリオが成立しません。隔離ファイルへの正規アクセスは、別の SA(隔離読取専用 SA)を system_admin が監査ログ付きで一時 impersonate する経路でのみ可能です。
全バケット共通のセキュリティ基準Common security baseline
| 項目 | 本構築での値 |
|---|---|
| 公開アクセス | 完全禁止(このバケットの公開アクセス禁止を強制) |
| アクセス制御方式 | Uniform Bucket-Level Access(バケット単位の IAM のみ。ファイル単位 ACL は使わない) |
allUsers / allAuthenticatedUsers | 存在しない(誤って付与されないよう構成済み) |
| リージョン | すべて asia-northeast1(東京) |
| 暗号化 | Google が管理する鍵(GMK) |
| CORS | 未検査バケットのみ https://portal.example.com +http://localhost:3000 を許可。共有リンクホストは不許可 |