S3 versioning keeps the old copy when you overwrite an object, and keeps a delete marker instead of really deleting when you call delete. It costs almost nothing, it takes one click, and everybody should turn it on.
It is also not a backup, and the difference is not pedantic. It is the difference between surviving a bad afternoon and surviving a bad actor.
What versioning is genuinely good at
Real problems it solves, today, with no further work:
- Someone overwrote
config.jsonwith an empty file. - A deploy script uploaded the wrong build over the right one.
- An
aws s3 rmremoved objects that turned out to matter. - A sync job with a bad
--deleteflag cleared a prefix.
All four are recoverable in minutes. That is a good day's return on one click, and if versioning is off on a bucket you care about, stop reading and go turn it on.
What it cannot do
Versioning lives inside the same bucket, in the same account, behind the same credentials as the data it protects.
| Threat | Versioning |
|---|---|
| Overwrote a file | Recovers it |
| Deleted a file | Recovers it |
| Attacker with your credentials runs a permanent delete of all versions | Everything is gone |
| Lifecycle rule expires noncurrent versions after 30 days | They are gone, on schedule, quietly |
| Bucket deleted, or account closed for non-payment | Gone |
| Region-wide failure | Unavailable |
| You need a copy an auditor can verify is outside the vendor | Cannot produce one |
The third row is the one that matters, and it is worth being blunt about it.
s3:DeleteObjectVersion permanently removes a specific version. An attacker who
has your credentials has that permission, and ransomware tooling has automated
this for years. Versioning is a feature your credentials control, so it defends
against accidents by people who are trying to be careful, and not at all against
someone who is not.
1
API call that erases every version
0
Extra credentials it needs beyond yours
30days
Typical noncurrent expiry that deletes your history for you
The lifecycle rule nobody remembers writing
There is a quieter failure here that catches careful teams.
Versioning without a lifecycle rule grows forever, so somebody eventually adds "expire noncurrent versions after 30 days" to control the bill. That is reasonable. It also means your versioning-based recovery window is now 30 days, enforced automatically, and nobody wrote that down as a retention decision. It was a cost decision that silently became a data policy.
What actually closes the gap
Three things, in order of effort:
- Object Lock, which is enforced below the permission layer, so a credential holder cannot delete a locked version. This is the one that stops the ransomware case.
- A copy in a different account, with different credentials, so a total compromise of the first account leaves the second intact.
- A copy in an open format you can open without the vendor, so recovery does not depend on anyone's continued cooperation.
Versioning is a good first layer. It was never meant to be the only one.
Where we sit
Our position is that the copy should land in a bucket you own, encrypted before it leaves the machine that produced it, and that we should hold none of the things required to read it.
That does mean the credential question lands on you, so we make the useful part easy: expiry that understands whether a newer good copy exists before it removes an older one, immutability expressed as its own setting rather than folded into retention, and a record per run of exactly where each copy went.
So, is it a backup?
Versioning is an undo button. A backup is a copy somewhere the thing that just went wrong cannot reach.
Keep the undo button. It is excellent and nearly free. Just do not let it be the reason you never built the second thing.