Enable Versioning for Object Recovery

Enable versioning for object recovery in this Cloud security essentials tutorial — hands-on steps, troubleshooting, and what to study next.

Focus: enable versioning for object recovery

Sponsored

You’ve built secure systems, locked down IAM, and encrypted data at rest — but what happens when a user accidentally deletes a critical object, or a malicious script wipes a bucket? Without versioning, that data is gone forever, and your recovery plan is a restore from backup that might be hours old. This lesson solves that pain by teaching you how to enable versioning for object recovery, turning your object storage into a time machine that keeps every version of every file, so you can roll back instantly.

The problem this lesson solves

Cloud object storage is cheap, scalable, and durable — but it’s also forgiving of mistakes. One wrong DeleteObject call, a compromised credential, or a faulty sync script can permanently destroy data that took weeks to generate. Many teams assume that because the cloud provider offers high durability, they don’t need extra protection. But durability means your data won’t be lost due to hardware failure — it says nothing about human error or malicious deletion.

Consider these real scenarios:

  • A developer accidentally runs aws s3 rm --recursive on the wrong bucket prefix.
  • A ransomware attack encrypts files and then deletes the originals.
  • A data pipeline overwrites a dataset with corrupt output, and nobody notices until the next day.

Without versioning, the only recovery option is to restore from a backup, which may be hours or days old — losing all changes made since. With versioning enabled, every upload creates a new version, and every delete creates a delete marker — so nothing is truly lost. This lesson gives you the practical skills to implement versioning in your cloud storage and use it as a first line of defense for object recovery.

Core concept / mental model

Think of versioning as an immutable ledger for your objects. In a non-versioned bucket, an object has one address and one state; overwriting it destroys the old data. In a versioned bucket, each object has an object key and a version ID. Every write (PUT) creates a new version, and every delete creates a marker that hides the current version but keeps it recoverable.

Here’s a visual model: without versioning, a file is a whiteboard where you can erase and rewrite. With versioning, you have a stack of transparent sheets — each new write adds a sheet on top, and you can always peel back to see previous states. The delete operation doesn’t erase the top sheet; it places a special “deleted” stamp on it, so the underlying sheets remain intact.

Key terms

  • Version ID – A unique identifier for each version of an object, generated by the storage service.
  • Delete marker – A special version of the object that represents a delete operation; it hides the current version but doesn’t remove it.
  • Current version – The latest version that will be returned when you GET the object without a version ID.
  • Noncurrent version – Any version older than the current one; normally invisible unless you request it explicitly.

Versioning works at the bucket level in most cloud providers, meaning all objects in the bucket are versioned — you can’t enable it per object. This is a deliberate design choice: it gives uniform protection and simplifies lifecycle management.

How it works step by step

Enabling versioning is a one-time operation, but using it effectively requires understanding the flow. Here’s the logical sequence:

  1. Create or select a bucket – Choose a bucket that will store your critical data. Remember: versioning can’t be disabled once enabled (only suspended), so choose wisely.
  2. Enable versioning – Using the cloud console, CLI, or SDK, set the bucket’s versioning status to Enabled.
  3. Upload and overwrite objects – Every PUT creates a new version. The old version becomes noncurrent.
  4. Delete an object – Instead of removing the data, a delete marker is added. The object is “hidden” but still recoverable.
  5. Recover a deleted object – To roll back, delete the delete marker or restore a specific noncurrent version.
  6. Manage versions over time – Use lifecycle rules to archive or delete old versions to control costs.

Why this order matters

Each step builds on the previous one. If you enable versioning before you store data, you protect every future write. If you enable it after data loss, you can’t recover the past. The best practice is to enable versioning on every bucket from day one, even if you think you don’t need it.

Hands-on walkthrough

Let’s make this concrete with AWS S3 as an example (the same concepts apply to Google Cloud Storage or Azure Blob Storage). We’ll use the AWS CLI and Python’s boto3 to enable versioning, simulate deletion, and recover an object.

1. Enable versioning with the AWS CLI

Open your terminal and run:

aws s3api put-bucket-versioning --bucket my-secure-bucket --versioning-configuration Status=Enabled

To verify it worked:

aws s3api get-bucket-versioning --bucket my-secure-bucket

Expected output:

{
    "Status": "Enabled"
}

2. Upload, overwrite, and delete an object

Create a file, upload it, then overwrite it, then delete it:

# Create initial content
echo "version 1" > report.txt

# Upload (creates version 1)
aws s3api put-object --bucket my-secure-bucket --key report.txt --body report.txt

# Overwrite (creates version 2)
echo "version 2" > report.txt
aws s3api put-object --bucket my-secure-bucket --key report.txt --body report.txt

# Delete (creates a delete marker)
aws s3api delete-object --bucket my-secure-bucket --key report.txt

Now list the object versions to see what happened:

aws s3api list-object-versions --bucket my-secure-bucket --prefix report.txt

The output will show three entries: two versions (with version IDs) and one delete marker with IsLatest: true.

3. Recover the deleted object with Python

Use boto3 to delete the delete marker, making the last version current again:

import boto3

# Create an S3 client
s3 = boto3.client('s3')

bucket = 'my-secure-bucket'
key = 'report.txt'

# List versions, find the delete marker
response = s3.list_object_versions(Bucket=bucket, Prefix=key)
for marker in response.get('DeleteMarkers', []):
    if marker['IsLatest']:
        # Delete the delete marker to restore the previous version
        s3.delete_object(
            Bucket=bucket,
            Key=key,
            VersionId=marker['VersionId']
        )
        print(f"Recovered object by removing delete marker {marker['VersionId']}")
        break

# Verify the object is back
obj = s3.get_object(Bucket=bucket, Key=key)
print(obj['Body'].read().decode())  # Output: version 2

Run the script and you should see:

Recovered object by removing delete marker 12345...
version 2

4. Restore a specific previous version

If you want to restore version 1 (the original), copy that version over the current one:

# Get the version ID of version 1 (from the earlier list)
version_id = 'YOUR_VERSION_ID_HERE'

# Copy that version to the same key, creating a new current version
s3.copy_object(
    Bucket=bucket,
    Key=key,
    CopySource={'Bucket': bucket, 'Key': key, 'VersionId': version_id}
)
print("Restored version 1 as the current version")

Now get_object returns version 1. This is a powerful recovery technique: you can go back to any point in time, not just the most recent version.

Compare options / when to choose what

Versioning is not the only recovery mechanism. Here’s how it compares with other strategies:

Option What it does Recovery time Cost When to use
Versioning Keeps every version of an object, including delete markers Seconds to minutes (self-service) Low per-object storage cost Critical data, frequent updates, compliance archives
Snapshots (block storage) Copy of entire volume at a point in time Minutes (if snapshot is recent) Medium — storage for each snapshot Databases, file systems, VMs
Backups (e.g., AWS Backup) Scheduled copies of data to a separate location Hours (restore process) Medium to high — separate storage Disaster recovery, long-term archival
Replication Copy objects to a different region/bucket Minutes to hours (dependent on provider) High — duplicating all writes Multi-region availability, compliance

When to choose versioning

  • You have object storage (S3, GCS, Blob) and want a low-cost, always-on recovery option.
  • You need point-in-time recovery of recent changes, down to seconds.
  • You want to protect against accidental deletion or overwrite without complex backup infrastructure.

When versioning is not enough

  • You need whole-system recovery — versioning protects individual objects, not entire buckets or regions. Use snapshots or backups for that.
  • You need to recover from a bucket deletion — versioning doesn’t help if the bucket itself is deleted. Enable bucket-level protection (like MFA delete) or use replication.
  • Cost control is critical — storing every version can balloon your storage bill. Use lifecycle rules to prune old versions.

Troubleshooting & edge cases

Versioning is still disabled after enabling

  • Check the bucket name – Did you use the correct bucket? It may be in a different region.
  • Permission issues – Ensure your IAM user has s3:PutBucketVersioning permission. Without it, the API call silently fails.
  • Wait for propagation – Some providers take a few seconds for the change to take effect. Wait and re-check.

My old version is not showing up

  • You may have enabled versioning after the data was written – Only new objects get version IDs. Existing objects have a null version ID and are not versioned.
  • You are listing noncurrent versions incorrectly – Use list-object-versions with a prefix, and filter by IsLatest: false.

Delete marker won’t go away

  • You may have multiple delete markers – Each delete operation adds a new marker. Remove all of them to fully restore.
  • You tried to delete the delete marker directly – You must delete using the exact version ID of the marker. Use the delete-object with VersionId as shown earlier.

Costs are rising unexpectedly

  • Every version costs money, even noncurrent ones. Set lifecycle policies to automatically move old versions to cheaper storage tiers (e.g., Glacier) or delete them after a retention period.
  • Versioning can’t be turned off, only suspended. Once suspended, no new versions are created, but existing versions remain and still accrue storage costs.

Edge case: MFA delete

For extra security, enable MFA delete on your versioning configuration. This requires multi-factor authentication to delete a version or change the versioning state — a powerful defense against ransomware and malicious insiders.

aws s3api put-bucket-versioning --bucket my-secure-bucket --versioning-configuration Status=Enabled,MFADelete=Enabled --mfa "arn:aws:iam::123456789012:mfa/device serial"

What you learned & what's next

You’ve learned how to enable versioning for object recovery, a cornerstone of cloud security. You can now:

  • Explain how versioning creates an immutable history of your objects, protecting against accidental deletion and overwrite.
  • Enable versioning on any bucket using the CLI, console, or SDK.
  • Recover deleted or overwritten objects using version IDs and delete marker removal.
  • Choose when versioning is the right tool compared to snapshots, backups, or replication.
  • Troubleshoot common issues like missing versions, rising costs, and delete marker consistency.

These skills directly reduce your blast radius in the event of human error or attack — a core tenet of the Cloud security essentials track. In the next lesson, you’ll build on this foundation by learning how to implement lifecycle policies to automate the retention and deletion of old versions, balancing security with cost efficiency. That lesson will show you how to keep your versioned data for as long as you need — and no longer.

Practice recap

Try this: enable versioning on a test bucket, upload an object, overwrite it, delete it, then recover it using the CLI or Python. Next, set up a lifecycle rule to move versions older than 30 days to Glacier. This hands-on practice will cement the concepts and prepare you for the next lesson on lifecycle policies.

Common mistakes

  • Enabling versioning after data loss — it only protects future writes, not past ones.
  • Forgetting to set permissions for s3:PutBucketVersioning — the API call silently fails, and you think it worked.
  • Not using lifecycle rules — version storage costs can spiral out of control if old versions are never pruned.
  • Trying to delete a delete marker without specifying the exact version ID — it won’t work and can create additional markers.
  • Assuming versioning protects against bucket deletion — it doesn’t. You need bucket-level protection like MFA delete or replication.

Variations

  1. Google Cloud Storage: enable versioning with gsutil versioning set on gs://your-bucket or via the console.
  2. Azure Blob Storage: enable blob soft delete instead, which is similar but also covers containers.
  3. AWS S3 Versioning supports MFA Delete for extra security, which requires a one-time password to delete a version.

Real-world use cases

  • A data engineer accidentally runs a recursive delete on an S3 bucket; versioning lets them restore all objects within minutes.
  • A ransomware attack encrypts and deletes original files; versioned objects are unreachable by the attacker and can be restored.
  • A CI/CD pipeline overwrites a production config with a corrupt file; versioning allows a quick rollback to the last good version.

Key takeaways

  • Versioning creates an immutable history for every object, including delete markers that allow recovery.
  • Enable versioning on every bucket from day one — it can’t protect data that was already lost.
  • Recovery is immediate: remove delete markers or copy a specific version back to current.
  • Versioning is lightweight and cheap compared to backups, but requires lifecycle policies to control costs.
  • Versioning does not protect against bucket deletion — combine it with MFA delete and replication for full security.
  • You can use versioning with any cloud provider: S3, GCS, and Azure all offer equivalent features.

Sponsored

Sponsored

Discussion

Questions, corrections, and tips help everyone reading this page.

0 comments

Add a comment

Shown publicly with your comment.

Be constructive · max 4,000 characters

No comments yet — start the thread.

Related tutorials, quizzes, and articles for this topic.