S3 Versioning & Lifecycle
S3 versioning keeps every object version under one key, so an overwrite or delete is non-destructive: the previous version is still there. Pair it with MFA Delete, Object Lock, and lifecycle rules and you have a low-cost, high-confidence answer to ransomware, accidental deletes, and compliance retention.
Enable, list, restore, lifecycle, and Object Lock
EXAMPLE
# 1) Enable versioning on a bucket
aws s3api put-bucket-versioning \
--bucket shop-uploads \
--versioning-configuration Status=Enabled
# Verify
aws s3api get-bucket-versioning --bucket shop-uploads
# -> { "Status": "Enabled" }
# 2) Upload a file twice — both versions live under the same key
aws s3 cp file.txt s3://shop-uploads/file.txt # version A
aws s3 cp file2.txt s3://shop-uploads/file.txt # version B (current)
aws s3api list-object-versions --bucket shop-uploads --prefix file.txt \
--query 'Versions[].{Id:VersionId,Latest:IsLatest,Size:Size,Modified:LastModified}'
# 3) Restore an older version (copy it onto itself with the older VersionId)
aws s3api copy-object \
--copy-source 'shop-uploads/file.txt?versionId=<OLDER_VERSION>' \
--bucket shop-uploads --key file.txt
# 4) 'Delete' is non-destructive — adds a Delete Marker on top
aws s3 rm s3://shop-uploads/file.txt
aws s3api list-object-versions --bucket shop-uploads --prefix file.txt \
--query 'DeleteMarkers[].{Id:VersionId,Latest:IsLatest}'
# Undelete: remove the Delete Marker
aws s3api delete-object --bucket shop-uploads --key file.txt --version-id <DELETE_MARKER_VID>
# 5) Lifecycle: expire old non-current versions after 90 days; keep 5
aws s3api put-bucket-lifecycle-configuration \
--bucket shop-uploads --lifecycle-configuration '{
"Rules": [{
"ID": "expire-old-versions",
"Status": "Enabled",
"Filter": {},
"NoncurrentVersionExpiration": { "NoncurrentDays": 90, "NewerNoncurrentVersions": 5 },
"AbortIncompleteMultipartUpload": { "DaysAfterInitiation": 7 }
}]
}'
# 6) MFA Delete — require a hardware/virtual MFA on every version delete
# (must be enabled by the bucket owner using their root credentials)
aws s3api put-bucket-versioning --bucket shop-uploads \
--versioning-configuration Status=Enabled,MFADelete=Enabled \
--mfa 'arn:aws:iam::123456789012:mfa/root 123456'
# 7) Object Lock — write-once-read-many for compliance / ransomware resistance
# Must be set at bucket creation time.
aws s3api create-bucket --bucket shop-locked \
--object-lock-enabled-for-bucket \
--region ap-southeast-2 \
--create-bucket-configuration LocationConstraint=ap-southeast-2
aws s3api put-object-lock-configuration --bucket shop-locked \
--object-lock-configuration 'ObjectLockEnabled=Enabled,Rule={DefaultRetention={Mode=COMPLIANCE,Days=180}}'
# 8) Restore from a delete spree — list everything that was deleted since T0
aws s3api list-object-versions --bucket shop-uploads \
--query 'DeleteMarkers[?LastModified > `2026-06-10T00:00:00Z`]'
# 9) Cost note: every version pays storage. The lifecycle policy above + a sane
# retention window keeps the bill bounded.
Why it matters
Combine versioning + lifecycle + Object Lock for a budget-friendly ransomware playbook. An attacker who compromises an IAM principal can overwrite or delete objects — but the prior versions remain, Object Lock blocks deletion below the retention floor, and lifecycle stops storage costs running away.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Example
Example
# Enable versioning to keep every revision. # Lifecycle rules tier old data to Glacier / delete after N days.Try it Yourself »
Discussion
Loading…