メインコンテンツまでスキップ

S3ファイルアップロードを統制する設計

画像や動画などのファイルについて、利用者、社内ポータル、受入S3、検査、承認、versionIdとchecksum固定、本番反映専用ロール、本番S3、監査を一枚にまとめた構成図

先に結論

S3へファイルを置く業務で採るべき方式は、利用者による「本番アップロード」ではなく、システムによる「検査済みファイルの本番昇格」である。

利用者は本番AWSアカウントへログインしない。社内ポータルから、申請ごとに発行された短時間のアップロード権限を使い、隔離された受入S3へファイルを送る。マルウェア検査、ファイル形式検査、業務承認が終わったら、承認したS3のversionIdとchecksumを固定する。本番反映専用ロールだけが、その版を本番S3へコピーするのだ。

この境界を作ると、端末侵害や誤操作の影響を受入領域へ閉じ込めやすい。感染していないことと、業務上正しいファイルであることも別の統制として扱える。画像や動画は代表例であり、文書、音声、アーカイブなどにも同じ設計を適用できる。

なぜ本番S3へ直接アップロードしてはいけないのか

本番アカウントへログインできる端末から手作業でPutObjectする方式は簡単である。ただし、認証した人、操作した端末、選択したファイル、本番へ置かれたオブジェクトが一つの経路へ密結合する。

この方式では、次の問題が同時に起こり得る。

  • 侵害端末から本番AWSの権限を悪用される
  • マルウェアを含むファイルがそのまま本番へ入る
  • 拡張子だけ画像や動画に見せた別形式のファイルが置かれる
  • 業務と関係ない大容量ファイルの置き場にされる
  • 承認したファイルと実際に配置したファイルが異なる
  • 同じオブジェクトキーへ承認後に別ファイルを上書きされる
  • 誰が何を検査し、誰がどの実体を承認したか追跡できない

IAM権限を少し狭くするだけでは、これらを分離できない。受入、検査、承認、本番反映を状態遷移として設計する必要があるのだ。

推奨フロー

段階処理主な統制
1. 申請目的、公開先、容量、期限、承認者を登録申請IDがなければアップロード不可
2. 受入社内ポータルが短時間の署名付きアップロード情報を発行固定キー、期限、容量、操作を限定
3. 自動検査マルウェアとファイルの実体を検査検査未完了・不能・失敗も不合格
4. 業務承認承認者が内容、目的、公開先を確認申請者と承認者を分離
5. 同一性固定versionId、checksum、サイズを承認記録へ保存承認後の差替えを防止
6. 本番昇格専用ロールが承認済みの版だけをコピー人と端末に本番書込権限を与えない
7. 監査申請、検査、承認、コピー、S3操作を記録一つの申請IDで証跡を相関

1. 社内ポータルで申請とアップロードを結び付ける

利用者はAWSコンソールではなく、社内認証されたアップロードポータルを使う。ポータルは申請IDを確認し、受入バケットの特定オブジェクトキーへだけ書き込める署名付きURLまたはPOST情報を短時間だけ発行する。

Amazon S3の署名付きURLは、URLを生成した主体の権限で、期限内のアップロードを許可する仕組みである。同じキーが既に存在すると置換され得るため、申請IDとランダム値を含む一意のキーを発行し、受入バケットではVersioningを有効にする必要がある。1

利用者へ許可するのは受入用の書込みだけでよい。ListBucketGetObjectDeleteObjectPutObjectTagging、本番バケットへのアクセスは与えない。

2. 受入S3を信頼しない隔離領域にする

アップロード前に感染を完全に排除するのではなく、受入S3へ不正ファイルが入る前提で境界を作る。検査完了までは利用者、本番処理、通常のプレビュー処理から読み出せないようにする。

GuardDuty Malware Protection for S3を使う場合、スキャン結果タグに基づくアクセス制御が可能であり、未スキャンまたは脅威検出済みオブジェクトへのアクセスをバケットポリシーで防げる。ライフサイクルを使った悪性オブジェクトの削除も構成できる。2

判定はfail closedにする。脅威なしを確認できた場合だけ次へ進め、脅威検出、未対応、失敗、タイムアウト、結果なしはすべて隔離または却下へ送るのだ。

2026年8月3日時点で、GuardDutyがマルウェアスキャンを試行するS3オブジェクトの最大サイズは100GBである。扱うファイルの上限がこれを超える場合は、AWS Supportへの確認またはECS、EC2、外部製品など別の検査方式が必要になる。3

3. ファイル種別ごとに実体を検査する

マルウェア検査は「業務で利用できるファイルか」を保証しない。拡張子とブラウザが送るContent-Typeも利用者入力なので、信頼できない。

Lambdaまたはコンテナで、すべてのファイルに共通する条件と、ファイル種別ごとの条件を確認する。

  • ファイルシグネチャ、MIME type、拡張子の整合
  • ファイルサイズ、破損有無、暗号化・圧縮状態
  • 画像の形式、縦横サイズ、色空間、メタデータ
  • 動画のコンテナ、映像・音声コーデック、解像度、再生時間、ストリーム数
  • 文書の形式、マクロ、埋め込みオブジェクト、外部参照
  • アーカイブの展開後サイズ、ファイル数、入れ子の深さ

許可条件は業務要件から明示する。例えば、画像なら「JPEGまたはPNG、最大50MB、最大12000×12000px」、動画なら「MP4、H.264、AAC、最大20GB、最大120分」のように定義する。大容量ファイルの解析やffprobeなどの処理がLambdaの実行時間、一時領域、メモリへ収まらない場合は、ECS/Fargateなどのコンテナ実行基盤へ分ける。

不要なメタデータや埋め込み要素を除きたい場合は、画像の再エンコード、文書の安全な形式への変換、MediaConvertによる動画の標準化などを行う。承認者が確認した変換後ファイルと、本番へ反映するファイルを同一にすることが重要なのだ。

4. 内容承認を自動検査から分離する

自動検査で判断できるのは、既知のマルウェア、ファイル構造、技術仕様などである。画像、動画、文書などの内容が申請目的に合うか、公開してよい内容か、対象環境が正しいかは業務承認が必要になる。

役割は次のように分ける。

役割できることできないこと
申請者申請、受入領域へのアップロード自己承認、本番書込み
検査ロール受入ファイルの読出し、検査結果の記録業務承認、本番書込み
承認者候補ファイルのプレビュー、承認・却下ファイル差替え、本番書込み
本番反映専用ロール承認済み版の読出し、固定先へのコピー任意ファイルの選択、未承認版のコピー

承認者へ本番書込権限を与えないことが大切である。承認という判断と、本番へ書き込む能力を同じ主体へ集めないのだ。

5. 承認対象を名前ではなく実体へ結び付ける

movie.mp4を承認した」という記録だけでは不十分である。同じキーへ別の内容をアップロードできるためだ。

承認記録には、最低限次を保持する。

  • 申請ID
  • 受入バケットとオブジェクトキー
  • S3 versionId
  • SHA-256などのchecksum
  • ファイルサイズと検査結果
  • 承認者と承認日時
  • 本番の配置先

S3のコピー元には特定のversion IDを指定でき、応答からコピーしたソースのversion IDも確認できる。したがって、本番反映処理は「最新の同名オブジェクト」ではなく、承認記録にある版をコピーする。4

checksumは転送時の完全性確認だけでなく、承認記録、検査結果、本番成果物を同じ実体へ結び付ける相関キーとして使う。ETagを常に内容ハッシュとみなさず、明示的なchecksumを保存する。

6. 本番書込みを専用ロールだけに限定する

本番S3へ書き込める主体はFilePromotionRoleのような専用ロールへ限定する。利用者、ポータル、検査ロール、承認者からの直接PutObjectは、IAMだけでなくバケットポリシーや必要に応じたSCPでも拒否する。

本番反映処理は、次の条件を再確認してからコピーする。

  • 申請が承認済み状態である
  • 検査結果がすべて合格である
  • versionId、checksum、サイズが承認記録と一致する
  • コピー先が申請で許可されたprefixである
  • 同じ申請IDが未反映、または再実行可能な状態である

非常時の手作業経路を残すなら、通常無効なbreak-glassロールとする。別担当者の承認、短時間セッション、理由入力、全操作の記録を必須にする。

アカウントを分けるか

重要な本番環境では、受入・検査アカウントと本番アカウントを分ける構成を推奨する。受入側が侵害されても、本番側で引き受けられる権限を、承認済み版の固定先へのコピーだけに限定できる。

小規模な構成では、同一アカウント内で受入、候補、本番のバケットとIAMロールを分けてもよい。ただし、アカウント管理者の侵害やポリシー設定ミスが全領域へ波及しやすい。簡素化してよいのはAWSアカウント数であり、受入と本番の権限境界ではないのだ。

監査と運用

CloudTrailでS3のPutObjectGetObjectDeleteObjectなどのオブジェクト操作を記録するには、S3データイベントを明示的に有効化する必要がある。データイベントは既定では記録されず、CloudTrailのイベント履歴にも出ない。5

申請IDを軸に、次の証跡を相関できるようにする。

  • 申請者、目的、対象、期限
  • 署名付きアップロード情報の発行
  • S3オブジェクトキー、versionId、checksum
  • マルウェア検査とファイル形式検査の結果
  • 承認者、判断、日時
  • 本番反映ロールの実行とコピー結果
  • 本番オブジェクトのversion IDとchecksum
  • 却下、失敗、再実行、非常時操作

本番バケットではS3 Block Public Accessを有効にし、ACLを使わない構成を基本とする。AWSはアカウントレベルで4設定すべてを有効にすることを推奨している。既存システムが公開アクセスへ依存していないことは適用前に確認する。6

未承認ファイルは7日から30日など業務上必要な期間で自動削除し、部署・利用者ごとの容量、件数、失敗率を監視する。長期保管を許すと、隔離領域が業務外ストレージへ変わってしまう。

最小構成と推奨構成

項目最小構成推奨構成
アカウント同一AWSアカウント受入・検査と本番を分離
入口社内認証済みポータル申請システムと連携したポータル
アップロード短時間の署名付きURL申請ID、固定キー、容量制約付き
検査GuardDutyと共通・種別別の形式検査GuardDuty、形式検査、必要に応じ正規化
承認既存申請システムプレビューと職務分離を備えた承認画面
状態管理DBまたはStep Functions再実行と例外処理を含むStep Functions
本番反映専用IAMロールクロスアカウント専用ロール
監査申請履歴とCloudTrail一つの申請IDで全証跡を相関

最初から大きなワークフロー製品を作る必要はない。社内認証、受入バケット、二つの自動検査、既存の承認経路、専用コピー処理があれば始められる。ただし、「検査前は読ませない」「承認対象の版を固定する」「人に本番書込みを与えない」の三点は省かない。

導入時の確認項目

  • 本番S3へ直接PutObjectできる主体が専用ロール以外に残っていないか
  • 利用者端末にAWSアクセスキーや本番セッションを持たせていないか
  • 署名付きURLのキー、期限、容量、再利用条件が限定されているか
  • 検査未完了、失敗、結果なしを合格として扱っていないか
  • 拡張子とContent-Type以外にファイル実体を検査しているか
  • 申請者と承認者が分離されているか
  • 承認記録にversionIdとchecksumがあるか
  • 本番反映時に承認済み版との一致を再確認しているか
  • CloudTrailのS3データイベントを有効にしているか
  • 未承認、感染、失敗ファイルの保持期限があるか
  • 非常時経路の承認、期限、監査が定義されているか
  • 100GBを超えるファイルの検査方式を別途決めているか

まとめ

統制されたS3ファイルアップロードは、アップロード画面を作る話だけではない。信頼していない受入領域から、検査と承認を通った特定の版だけを本番へ昇格させる仕組みである。

シンプルさを保つなら、サービス数を増やす前に境界を明確にする。利用者は受入だけ、検査は判定だけ、承認者は判断だけ、本番反映ロールは固定されたコピーだけを担う。この分離が、端末侵害、マルウェア、私的利用、誤反映を同時に小さくするのだ。

参考資料

Footnotes

  1. AWS, "Uploading objects with presigned URLs" https://docs.aws.amazon.com/AmazonS3/latest/userguide/PresignedUrlUploadObject.html

  2. AWS, "Supportability of Amazon S3 features" https://docs.aws.amazon.com/guardduty/latest/ug/supported-s3-features-malware-protection-s3.html

  3. AWS, "Quotas in Malware Protection for S3" https://docs.aws.amazon.com/guardduty/latest/ug/malware-protection-s3-quotas-guardduty.html

  4. AWS, "CopyObject" https://docs.aws.amazon.com/AmazonS3/latest/API/API_CopyObject.html

  5. AWS, "Amazon S3 CloudTrail events" https://docs.aws.amazon.com/AmazonS3/latest/userguide/cloudtrail-logging-s3-info.html

  6. AWS, "Blocking public access to your Amazon S3 storage" https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-control-block-public-access.html