「スクリプトのバグでS3からファイルを誤削除してしまい、復元できなかった」
こういった事故は、S3をデフォルト設定のまま使い続けたときに起きやすいインシデントです。S3は高可用性なオブジェクトストレージですが、上書きや削除への保護機能はデフォルトでは無効になっています。バージョニングとライフサイクルポリシーを組み合わせることで、誤操作からデータを守りながらストレージコストを最適化できます。
この記事では、AWS CLIを使ってS3バケットのバージョニングを有効化し、削除マーカーの仕組みを理解した上で、ライフサイクルポリシーによるGlacier移行とバージョン管理の設計方法を実践的に解説します。クロスリージョンレプリケーション(CRR)によるリージョン間冗長化の手順も含めます。
動作確認環境: Amazon Linux 2023 / AWS CLI 2.17.x / S3(ap-northeast-1リージョン)
この記事のポイント
・バージョニング有効化は put-bucket-versioning --status Enabled の1コマンド
・削除しても削除マーカーが残るため list-object-versions で復元できる
・ライフサイクルポリシーで古いバージョンをGlacierに移行してコストを削減
・CRRはバージョニングが前提条件。既存オブジェクトには自動適用されない点に注意
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
なぜS3でバージョニングが必要なのか
S3はAWSで最もよく使われるストレージサービスです。静的Webサイトのホスティング、EC2インスタンスのデプロイアーティファクト保管、CloudTrailログの保存、Terraformのtfstate管理——用途は多岐にわたります。デフォルト状態のS3バケットには大きなリスクがあります。
・上書き保護がない: 同じキー名でPUTリクエストを送ると、以前のオブジェクトが問答無用で置き換わります。デプロイスクリプトにバグがあった場合、本番の設定ファイルが壊れたバージョンで上書きされます
・削除保護がない: DELETEリクエストを送るとオブジェクトは即座に消えます。バッチスクリプトが誤ってバックアップ先のバケットを対象にしたとき、全データが消えることになります
・復元手段がない: バージョニングなしでは削除・上書きされたオブジェクトを復元する方法がありません
この問題を解決するのがS3バージョニングです。バージョニングを有効化すると、同じキーへの上書きや削除が行われても、すべての履歴がバージョンIDとして保存されます。特定時点の状態に戻すことができるため、人的ミスや不正操作からデータを守れます。
S3バージョニングの有効化と確認手順
1. バケットのバージョニングを有効化する
バージョニングはput-bucket-versioning コマンドで有効化します。一度有効化したバージョニングは「無効化」できません(「一時停止(Suspended)」への変更のみ可能)。本番バケットに適用する前に、必ずテスト用バケットで動作を確認してください。# バージョニングを有効化 aws s3api put-bucket-versioning \ --bucket my-production-bucket \ --versioning-configuration Status=Enabled # バージョニングの状態を確認 aws s3api get-bucket-versioning \ --bucket my-production-bucket
{ "Status": "Enabled", "MFADelete": "Disabled" }
Status: Enabled が表示されれば有効化完了です。2. バージョン一覧を確認する
バージョニング有効化後にオブジェクトをアップロードすると、各バージョンにユニークなバージョンIDが付与されます。# 同じキーに2回アップロードして上書きを再現 echo "version 1" | aws s3 cp - s3://my-production-bucket/config.txt echo "version 2" | aws s3 cp - s3://my-production-bucket/config.txt # バージョン一覧を表示 aws s3api list-object-versions \ --bucket my-production-bucket \ --prefix config.txt
{ "Versions": [ { "Key": "config.txt", "VersionId": "BspIL8pXg_VK5Skxugcw_sdkSOj5NU.s", "IsLatest": true, "Size": 10, "LastModified": "2026-07-08T05:00:00.000Z" }, { "Key": "config.txt", "VersionId": "eYkUMj4f1rJ3n4GMRqBv7k39sNQ27h7P", "IsLatest": false, "Size": 10, "LastModified": "2026-07-08T04:58:00.000Z" } ] }
IsLatest: true のバージョンが最新です。バージョンIDを指定することで以前のバージョンを取得・復元できます。削除マーカーの仕組みと誤削除からの復元
バージョニングが有効な状態でaws s3 rm や aws s3api delete-object(バージョンID指定なし)を実行すると、オブジェクトは完全に消えません。「削除マーカー(Delete Marker)」と呼ばれる特殊なバージョンが追加されます。・通常の s3 rm 実行: 削除マーカーが IsLatest として追加される。
aws s3 ls には表示されなくなるが、バージョン一覧には残っている・バージョンID指定の削除: 指定したバージョンのみが物理削除される(復元不可)
削除マーカー自体にはデータが含まれておらず、ストレージ使用量はほぼゼロです。
1. 誤削除したオブジェクトを復元する
# 誤削除後のバージョン一覧(DeleteMarkersセクションに削除マーカーが現れる) aws s3api list-object-versions \ --bucket my-production-bucket \ --prefix config.txt \ --query "DeleteMarkers" # 出力例 # [ # { # "Key": "config.txt", # "VersionId": "k7qFz3Ge0nVo5MFH9E7g5L8xdHJfmCpQ", # "IsLatest": true, # "LastModified": "2026-07-08T06:00:00.000Z" # } # ] # 削除マーカーを削除することで復元する aws s3api delete-object \ --bucket my-production-bucket \ --key config.txt \ --version-id k7qFz3Ge0nVo5MFH9E7g5L8xdHJfmCpQ
aws s3 ls で再度表示されるようになります。2. 特定バージョンに戻す
# 古いバージョンをダウンロードして内容確認 aws s3api get-object \ --bucket my-production-bucket \ --key config.txt \ --version-id eYkUMj4f1rJ3n4GMRqBv7k39sNQ27h7P \ /tmp/config.txt.v1 cat /tmp/config.txt.v1 # 問題なければ古いバージョンを最新としてコピー aws s3 cp \ "s3://my-production-bucket/config.txt" \ "s3://my-production-bucket/config.txt" \ --source-version-id eYkUMj4f1rJ3n4GMRqBv7k39sNQ27h7P
AWSの冗長設計を体系的に学びたい方には、AWSエンジニアが身につける実践的な冗長設計の考え方もあわせてご覧ください。
ライフサイクルポリシーでコスト最適化(Glacier移行・バージョン有効期限)
バージョニングを有効化しただけでは、古いバージョンが永遠にS3 Standardで保管されてコストが膨らみます。ライフサイクルポリシーを設定して、一定期間経過後に安いストレージクラスへ移行・削除するルールを自動化します。S3のストレージクラスとコスト(東京リージョン、概算):
・S3 Standard: $0.025/GB/月。頻繁にアクセスするデータ向け
・S3 Standard-IA(低頻度アクセス): $0.019/GB/月。月1回未満のアクセスが目安
・S3 Glacier Instant Retrieval: $0.005/GB/月。ミリ秒単位で取得可能なアーカイブ
・S3 Glacier Flexible Retrieval: $0.0045/GB/月。3~12時間で取得するアーカイブ
・S3 Glacier Deep Archive: $0.002/GB/月。12~48時間で取得する最安アーカイブ
1. ライフサイクルポリシーのJSONを作成する
# lifecycle.json { "Rules": [ { "ID": "archive-and-expire-versions", "Status": "Enabled", "Filter": {}, "Transitions": [ { "Days": 30, "StorageClass": "STANDARD_IA" }, { "Days": 90, "StorageClass": "GLACIER_IR" } ], "NoncurrentVersionTransitions": [ { "NoncurrentDays": 30, "StorageClass": "GLACIER_IR" } ], "NoncurrentVersionExpiration": { "NoncurrentDays": 365, "NewerNoncurrentVersions": 5 }, "AbortIncompleteMultipartUpload": { "DaysAfterInitiation": 7 } } ] }
・Transitions(最新バージョンの移行): 作成から30日でStandard-IA、90日でGlacier IRへ自動移行
・NoncurrentVersionTransitions(古いバージョンの移行): 新バージョンに切り替わってから30日でGlacier IRへ移行
・NoncurrentVersionExpiration: 古いバージョンを365日後に削除。ただし最新5バージョンは保持
・AbortIncompleteMultipartUpload: 7日以上放置されたマルチパートアップロードを自動削除(コスト漏れ防止)
2. ライフサイクルポリシーを適用する
# ポリシーを適用 aws s3api put-bucket-lifecycle-configuration \ --bucket my-production-bucket \ --lifecycle-configuration file://lifecycle.json # 設定内容を確認 aws s3api get-bucket-lifecycle-configuration \ --bucket my-production-bucket
クロスリージョンレプリケーション(CRR)でリージョン間冗長化する
S3はリージョン内で複数のAZにデータを分散保管しているため、AZ障害に対しては十分な冗長性があります。しかし「東京リージョン全体に影響する大規模障害」や「誤操作による全データ削除」には対応できません。クロスリージョンレプリケーション(CRR)を使うと、オブジェクトを別リージョンのバケットへ非同期でレプリケーションできます。S3の高い耐久性に加えて地理的な冗長性を確保したい場合に有効な設計です。
1. 事前準備(バージョニングと宛先バケットの作成)
CRRを設定するには、送信元・宛先バケットの両方でバージョニングが有効になっている必要があります。# 宛先バケットを大阪リージョンに作成 aws s3api create-bucket \ --bucket my-replica-bucket-osa \ --region ap-northeast-3 \ --create-bucket-configuration LocationConstraint=ap-northeast-3 # 宛先バケットのバージョニングを有効化 aws s3api put-bucket-versioning \ --bucket my-replica-bucket-osa \ --versioning-configuration Status=Enabled \ --region ap-northeast-3
2. IAMロールを作成してS3レプリケーション権限を付与する
# trust-policy.json(S3がAssumeRoleできるよう信頼ポリシーを設定) { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "s3.amazonaws.com" }, "Action": "sts:AssumeRole" } ] } # IAMロールを作成 aws iam create-role \ --role-name s3-crr-role \ --assume-role-policy-document file://trust-policy.json # 必要な最小権限(本番では最小権限のインラインポリシーを作成すること) # 送信元: s3:GetObjectVersionForReplication, s3:GetObjectVersionAcl, s3:ListBucket # 宛先: s3:ReplicateObject, s3:ReplicateDelete, s3:ReplicateTags aws iam attach-role-policy \ --role-name s3-crr-role \ --policy-arn arn:aws:iam::aws:policy/AmazonS3FullAccess
3. レプリケーション設定を適用する
# replication.json(ACCOUNT-IDは自分のAWSアカウントIDに変更) { "Role": "arn:aws:iam::ACCOUNT-ID:role/s3-crr-role", "Rules": [ { "ID": "replicate-all-to-osaka", "Status": "Enabled", "Filter": {}, "Destination": { "Bucket": "arn:aws:s3:::my-replica-bucket-osa", "StorageClass": "STANDARD_IA" }, "DeleteMarkerReplication": { "Status": "Enabled" } } ] } # 送信元バケットにレプリケーション設定を適用 aws s3api put-bucket-replication \ --bucket my-production-bucket \ --replication-configuration file://replication.json # 設定確認 aws s3api get-bucket-replication \ --bucket my-production-bucket
よくある落とし穴とトラブルシュート
1. バージョニング有効化前のオブジェクトのバージョンIDが「null」になる
バージョニングを有効化する前に既にあったオブジェクトにはVersionId: null(ヌルバージョン)が付与されます。バージョニング有効化後に同じキーを上書きすると、nullバージョンと新バージョンが共存します。ヌルバージョンを削除したい場合は --version-id "null" を指定します。# ヌルバージョン(バージョニング有効化前のオブジェクト)を削除 aws s3api delete-object \ --bucket my-production-bucket \ --key legacy-config.txt \ --version-id "null"
2. ライフサイクルポリシーがすぐに反映されない
put-bucket-lifecycle-configuration を実行してから、S3が実際に移行・削除処理を開始するまでに最大24時間かかります。「設定したのに古いバージョンが残っている」という問い合わせで最も多いのがこのケースです。翌日改めて確認してください。3. CRRでAccessDeniedエラーが出る
レプリケーションに使用するIAMロールに権限が不足するとAccessDeniedになります。送信元バケットへのs3:GetObjectVersionForReplication、宛先バケットへの s3:ReplicateObject が最低限必要です。CloudTrailのログでどの権限が不足しているか確認できます。4. 削除マーカーが宛先バケットにレプリケーションされない
CRR設定のデフォルトでは削除マーカーはレプリケーションされません。DeleteMarkerReplication: Enabled を明示的に設定する必要があります。送信元で誤削除したときに宛先でも消えては困るケースでは、あえて Disabled にしておく設計もあります。要件に合わせて選択してください。本記事のまとめ
S3バージョニング・ライフサイクルポリシー・CRRの主要コマンドをまとめます。| やりたいこと | コマンド |
|---|---|
| バージョニングを有効化する | aws s3api put-bucket-versioning --bucket NAME --versioning-configuration Status=Enabled |
| バージョニング状態を確認する | aws s3api get-bucket-versioning --bucket NAME |
| バージョン一覧を確認する | aws s3api list-object-versions --bucket NAME --prefix KEY |
| 削除マーカーを除去して復元する | aws s3api delete-object --bucket NAME --key KEY --version-id DELETE-MARKER-ID |
| 特定バージョンを取得する | aws s3api get-object --bucket NAME --key KEY --version-id VERSION-ID /tmp/file |
| ライフサイクルポリシーを適用する | aws s3api put-bucket-lifecycle-configuration --bucket NAME --lifecycle-configuration file://lifecycle.json |
| レプリケーション設定を適用する | aws s3api put-bucket-replication --bucket NAME --replication-configuration file://replication.json |
put-bucket-versioning でバージョニングを有効化することを推奨します。AWSの冗長設計をシステム全体の設計思想から体系的に学びたい方には、AWSエンジニアが身につける実践的な冗長設計の考え方をご覧ください。
AWSのデータ保護設計を「実務の型」として身につけませんか?
S3バージョニングの設定手順は調べれば分かります。でも「どのライフサイクルルールがコストと復旧要件のバランスを取れているか」を設計判断できますか?
現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、『Linuxサーバー構築入門マニュアル(図解60P)』を完全無料でプレゼントしています。
「独学の時間がもったいない」「プロから直接、現場の技術を最短で学びたい」という本気の方には、2日で実務レベルのスキルが身につく【初心者向けハンズオンセミナー】も開催しています。
3,100名以上が実践した「型」を無料で公開中
プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。
登録10秒/合わなければ解除3秒 / 詳細はこちら

無料メルマガで学習を続ける
Linuxの実践スキルをメールで毎週お届け。
登録は1分、解除もいつでも可。
登録無料・いつでも解除できます