0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【AWS】S3でバージョニングを有効化してみた、その後に効いてくる削除マーカーとライフサイクルの話

0
Posted at

はじめに

AWSのハンズオンでS3バケットにバージョニングを有効化してみたら、「有効化」自体は一瞬なのに、そのあとに知っておくべきことが想像より多いと気づきました。削除したのにファイルが消えない、請求が静かに増える、一度ONにすると戻せない——このあたりは公式ドキュメントを読むまでピンときませんでした。

この記事は、S3バージョニングの「有効化したあとの世界」を初学者向けに整理した学習メモです。仕組み(3つの状態・削除マーカー・null バージョン)から、実務で効いてくるコスト管理(ライフサイクル)まで、図を交えて順に見ていきます。

忙しい人向けの結論(3行):

  • バージョニングは「上書き・誤削除しても過去版が残る」保険。ただし一度有効化すると未設定には戻せない(停止まではできる)
  • 削除しても「削除マーカー」が乗るだけで中身は残る。だから復元しやすい反面、放置すると過去版のストレージ課金が積み上がる
  • 入れっぱなしにせず、ライフサイクルルールで「古い版を自動で整理」するところまでがワンセット

参考リンク

S3バージョニングの概要(AWS公式)

削除マーカーとバージョン削除の挙動(AWS公式)

ライフサイクルで過去版を減らしてコストを下げる(AWS Storage Blog)

ライフサイクルと他のバケット設定の相互作用(MFA Delete との併用不可・AWS公式)

aws_s3_bucket_versioning リソース(Terraform Registry)

そもそもバージョニングって何?

ひとことで言うと、同じ名前(キー)のオブジェクトを上書き・削除しても、前の版を消さずに取っておく機能です。Wordの変更履歴やGitのコミット履歴に近いイメージ。

バージョニングなしのS3だと、photo.jpg を新しい内容で上書きした瞬間、古い photo.jpg は消えます。誤って古いファイルを上げてしまっても、もう戻せない。バージョニングを有効にしておくと、上書きのたびに新しい版が積まれ、古い版は version_id 付きでそのまま残ります。

何がうれしいのか。誤削除・誤上書きからの復旧はもちろん、最近はランサムウェア対策の文脈でも語られます。暗号化されてしまった版の「一つ前」に戻せるからです。

バージョニングには3つの状態がある

ここが最初の「へえ」ポイントでした。バージョニングは ON/OFF の2択ではなく、3つの状態を持ちます。

image.png

  • 未設定(Unversioned): バケット作成時のデフォルト。version_id は付かない
  • 有効(Enabled): 上書き・削除しても過去版が残る。各版に version_id が付く
  • 停止(Suspended): 新しく入れるオブジェクトは version_id が null になる。ただし、すでにある過去版は消えずに残る

一番の注意点はこれです。一度「有効」にしたバケットは、「未設定」には二度と戻せません。やめたいときにできるのは「停止(Suspend)」までで、停止は新しい版を作らなくするだけ。過去に溜まった版は残り続けます(=課金も続く)。だから「とりあえずON」の前に、後述のコスト管理まで頭に入れておくと安全です。

「削除したのに消えない」謎 ―― 削除マーカーの正体

自分が最初につまずいたのがこれでした。バージョニング有効なバケットでオブジェクトを削除したのに、バージョン一覧に残っていて「消えてないじゃん」と混乱したんです。あなたも同じところで引っかかっていませんか?

種を明かすと、version_id を指定しない普通の削除(DELETE)は、オブジェクトを物理削除しません。代わりに削除マーカーという“フタ”を最新版として乗せるだけなんです。

image.png

  • GET すると 404 が返る(=アプリからは「消えた」ように見える)
  • でも過去版(v1, v2 …)は生きている
  • だから削除マーカーを外せば、そのまま元に戻せる

「じゃあ本当に消したいときは?」——そのときは version_id を指定して削除します。指定した版だけがストレージから物理削除され、これは元に戻せません。

つまりバージョニング中の削除には2種類あるわけです。フタをするだけの「普通の削除」と、版を名指しで消す「完全削除」。この違いが分かると、次のコストの話がスッと入ってきます。

version_id が "null" になるやつ

version_id まわりでもう一つ混乱しやすいのが null バージョンの存在です。次の2ケースで version_id が null になります。

  • 有効化する前にバケットへ置いていたオブジェクト(後から有効化しても、その版の id は null のまま)
  • 停止(Suspended)状態のときに新しく入れたオブジェクト

null 版はキーごとに1つしか持てず、同じキーで入れ直すと上書きされます。Terraform でハンズオンしていると、「バージョニング有効化」と「オブジェクトのアップロード」の順番しだいで version_id が null になってしまう、という順序依存に出くわします。この対処は最後のTerraform節で触れます。

AWSは「バケットのバージョニングを初めて有効化したら、オブジェクトへの書き込み(PUT/DELETE)を始める前に15分ほど待つこと」を推奨しています。有効化直後に一気に書き込むと、設定が行き渡る前の版が意図せず null 扱いになることがあるためです。

落とし穴:バージョンは黙って課金され続ける

ここが実務でいちばん効いてくる話です。過去版(noncurrent version)も、当然ながらS3のストレージ課金の対象になります。

バージョニングが便利なのは「消しても残る」から。でもそれは裏を返すと、上書きや削除を繰り返すほど、見えないところで版が積み上がり、ストレージ料金がじわじわ増えるということでもあります。同じキーに何度もデプロイするバケットや、ログを上書き保存するバケットだと、気づいたときには過去版が本体の何倍にもなっていた——というのはよく聞く事故です。

前の削除マーカーの話ともつながります。普通に消したつもりでも版は残るので、意識して整理しない限りストレージは減りません。

対策:ライフサイクルで“世代管理”する

放置すると増えるなら、自動で整理すればいい。それがS3のライフサイクルルールです。バージョニングとライフサイクルは、ほぼセットで組むものだと思っておくと良いです。

image.png

よく使う組み合わせはこの2つ。

  • 古い版の失効(NoncurrentVersionExpiration): 過去版になってから N 日たったら自動で完全削除する
  • 最新◯世代だけ残す(newer_noncurrent_versions): 直近の版は守りつつ、それより古い版だけ消す

たとえば「過去版は30日で失効、ただし最新3世代は残す」とすれば、直近のロールバック余地を確保しつつ、古い版の課金は止められます。消すのが惜しい版は、削除ではなくGlacierなどの安いストレージクラスへ移す(transition)手もあります。

失効した版のストレージ料金はかかりません。ただし実際の削除は非同期で、失効のマークが付いてから物理削除まで少しラグがあります。「今すぐ全部消えて課金ゼロ」ではなく「マークが付いた時点で課金対象から外れる」と理解しておくと安心です。

もう一段の守り:MFA Delete

もっと堅くしたいバケットには MFA Delete という仕組みがあります。版の完全削除や、バージョニング状態の変更(停止など)に、MFA(多要素認証)のコードを要求する設定です。

  • 効果: 誤操作や、認証情報を奪われたときの「版ごと消される」攻撃を防ぎやすい
  • クセ: 有効化できるのはバケット所有者(ルートユーザー)だけで、マネジメントコンソールからは設定できず、CLI/API から行う必要がある

普段の学習では必須ではありませんが、「消されたら本当に困る」バケット(監査ログ、バックアップなど)では検討する価値があります。

一つ大事な制約があります。MFA Delete とライフサイクル設定は、同じバケットで併用できません。ライフサイクルが有効なバケットに MFA Delete を付けようとすると InvalidBucketState(Mfa Authentication is not supported on a bucket with lifecycle configuration)で弾かれます。つまり「古い版はライフサイクルで自動削除しつつ、削除には MFA も要求する」は同一バケットでは成立しません。自動整理を取るか、MFA による削除ガードを取るか——用途ごとにバケットを分けて設計します。

Terraform での有効化(ハンズオン)

最後に、Terraform での最小コードを置いておきます。自分はこの構成でハンズオンしました。バージョニングは aws_s3_bucket 本体ではなく、独立した aws_s3_bucket_versioning リソースで設定します。

versioning.tf
# S3バケット名は全世界で一意が必要。random_id で衝突を避ける
resource "random_id" "suffix" {
  byte_length = 4
}

resource "aws_s3_bucket" "site" {
  bucket = "handson-versioning-${random_id.suffix.hex}"
}

# バージョニングを有効化
resource "aws_s3_bucket_versioning" "site" {
  bucket = aws_s3_bucket.site.id
  versioning_configuration {
    status = "Enabled"
  }
}

そして、さきほど触れた「順序依存」の対処です。バージョニングの有効化リソースより先にオブジェクトがアップされると version_id が null になってしまうので、depends_on でアップロードを後回しにします。

object.tf
resource "aws_s3_object" "index" {
  bucket = aws_s3_bucket.site.id
  key    = "index.html"
  source = "index.html"

  # バージョニング有効化のあとに上げる(先に上げると version_id=null になる)
  depends_on = [aws_s3_bucket_versioning.site]
}

depends_on が保証するのは Terraform 上の作成順序(並列適用で先に上がってしまうのを防ぐ)だけで、AWS側でバージョニング設定が完全に行き渡る前述の「15分」までは面倒を見てくれません。重要なオブジェクトを扱うなら、有効化と投入を別々の apply に分ける、もしくは15分空けるなどの配慮をしておくと確実です。ハンズオンの範囲では depends_on で十分実用になります。

コスト管理のライフサイクルも Terraform で書けます。「過去版は30日で失効、最新3世代は残す」はこう書きます。

lifecycle.tf
resource "aws_s3_bucket_lifecycle_configuration" "site" {
  bucket = aws_s3_bucket.site.id

  # ライフサイクルはバージョニングが有効になってから
  depends_on = [aws_s3_bucket_versioning.site]

  rule {
    id     = "expire-noncurrent"
    status = "Enabled"

    filter {} # バケット全体を対象にする

    noncurrent_version_expiration {
      noncurrent_days           = 30
      newer_noncurrent_versions = 3
    }
  }
}

versioning_configuration.status には Disabled という値もありますが、これは「もともとバージョニングを使っていないバケット」をTerraform管理下に取り込む(import する)ための値です。Enabled から Disabled に戻すことはできません。AWSのAPIが未設定状態への復帰をサポートしておらず、エラーになります。停止したいときは Suspended を指定します。

まとめ

S3のバージョニングは「有効化」自体は一瞬ですが、そのあとの挙動を知らないとハマります。振り返ると、要点はこの3つでした。

  • 状態は3つ(未設定 → 有効 → 停止)。有効化したら未設定には戻せない
  • 削除は「削除マーカーを乗せるだけ」。復元しやすいが、放置すると過去版が課金され続ける
  • だからライフサイクル(古い版の失効+残す世代数)で自動整理するところまでがワンセット

自分はここまでハンズオンで確認して、「バージョニングは“入れて終わり”じゃなくて“整理まで含めて設計するもの”なんだ」と腹落ちしました。次は削除マーカーからの復元や、Glacierへの transition を実際に試して、挙動を目で見てみたいと思っています。

もしあなたがすでにバージョニング有効のバケットを運用しているなら、一度ストレージの内訳(過去版がどれくらい溜まっているか)を覗いてみると面白いかもしれません。「え、こんなに?」となったら、それがライフサイクルの出番です。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?