Overview
Versioning allows to store multiple variants of an object in the same bucket.
Variants – also called versions – are identified with a unique version id in object’s metadata VersionId
.
Every PUT action adds a new version that becomes current (meaning a GET will retrieve this version).
The previous current version of the object becomes non current and other versions are kept unmodified.
A DELETE action adds a delete marker that becomes current (meaning a GET will result in a “NoSuchKey” or “Not Found” error).
A delete marker contains no data.
The current object’s version, whether it’s data or a delete marker, is identified with the boolean metadata IsLatest
value “true”.
Object’s versions are never deleted unless you specify a version id .
If a delete marker is current, a GET (without version id) will result in a NoSuchKey
error.
If an object’s version is current, a GET (without version id) will retrieve this version.
Typical use cases: recover from accidental deletion or overwrite (unintended user actions or application failure).
Use cases with AWS CLI
AWS CLI (Command Line Interface) is an open source tool that enables you to configure and use object storage with commands in a text interface (Linux shell or Windows command line).
A user guide is available at https://docs.aws.amazon.com/cli/latest/userguide/ .
Prerequisite : enable versioning
Versioning can be enabled at bucket level.
root@mytest ~]# aws --endpoint-url https://s3-region01.cloudavenue.orange-business.com s3api put-bucket-versioning --bucket mydemobucket --versioning-configuration Status=Enabled
Check versioning state
Versioning enabled :
[root@mytest ~]# aws --endpoint-url https://s3-region01.cloudavenue.orange-business.com s3api get-bucket-versioning --bucket mydemobucket { "Status": "Enabled" }
Versioning suspended (after being enabled) :
[root@mytest ~]# aws --endpoint-url https://s3-region01.cloudavenue.orange-business.com s3api get-bucket-versioning --bucket mydemobucket { "Status": "Suspended" }
In default state (versioning has not been enabled), the request produces no output :
[root@mytest ~]# aws --endpoint-url https://s3-region01.cloudavenue.orange-business.com s3api get-bucket-versioning --bucket mydemobucket
List object’s version and delete marker
Below, a list of object’s version and delete marker after the following actions (in a new bucket with versioning enabled):
PUT object1 (size 102400 bytes)
DELETE object1
PUT object1 (size 1048576 bytes)
What happened :
The initial PUT created a version that is not current anymore ("IsLatest": false
) because of action 2.
The DELETE created a delete marker that is not current anymore because of action 3.
The last PUT created a version that is current ("IsLatest": true
).
If you GET object1, you will retrieve the 1048576 bytes object.
Note that the list (JSON format) contains 2 arrays, one for versions and the other for delete markers.
[root@mytest ~]# aws --endpoint-url https://s3-region01.cloudavenue.orange-business.com s3api list-object-versions --bucket mydemobucket { "Versions": [ { "ETag": "\"2bd0a7886355c628b78b0052673d7789\"", "Size": 1048576, "StorageClass": "STANDARD", "Key": "object1", "VersionId": "3938333335303336323031393630393939393939524730303120203232382e3832373832333033332e3236", "IsLatest": true, "LastModified": "2022-10-05T09:56:38.038000+00:00", "Owner": { "DisplayName": "QUALIF_LXLEGUEN", "ID": "44f9cfd39fe76487c5213ec20c4f6a5545ef9e52d1cbe4ca0e38f87b9d2acdea" } }, { "ETag": "\"acd8a242d5b76bf7716fe4e7018864c1\"", "Size": 102400, "StorageClass": "STANDARD", "Key": "object1", "VersionId": "3938333335303336323839313537393939393939524730303120203232382e3832373832303835342e3234", "IsLatest": false, "LastModified": "2022-10-05T09:55:10.841000+00:00", "Owner": { "DisplayName": "QUALIF_LXLEGUEN", "ID": "44f9cfd39fe76487c5213ec20c4f6a5545ef9e52d1cbe4ca0e38f87b9d2acdea" } } ], "DeleteMarkers": [ { "Owner": { "DisplayName": "QUALIF_LXLEGUEN", "ID": "44f9cfd39fe76487c5213ec20c4f6a5545ef9e52d1cbe4ca0e38f87b9d2acdea" }, "Key": "object1", "VersionId": "3938333335303336323336323436393939393939524730303120203232382e3832373832323131332e3235", "IsLatest": false, "LastModified": "2022-10-05T09:56:03.753000+00:00" } ] }
Cancel previous action using DELETE with version id
By deleting either a version or a delete marker with a version id, it’s possible to go back in time (cancel previous actions).
Using the previous example (above), let’s go back to initial state in 2 steps:
cancel the 2nd PUT by deleting a version (the delete marker becomes current)
# cancel the 2nd PUT by deleting a version<br />(the delete marker becomes current)<br /><syntaxhighlight lang="Shell">[root@mytest ~]# aws --endpoint-url https://s3-region01.cloudavenue.orange-business.com s3api delete-object --bucket mydemobucket --key object1 --version-id 3938333335303336323031393630393939393939524730303120203232382e3832373832333033332e3236 { "VersionId": "3938333335303336323031393630393939393939524730303120203232382e3832373832333033332e3236" } [root@mytest ~]# aws --endpoint-url https://s3.flexible-datastore.orange-business.com s3api list-object-versions --bucket mydemobucket { "Versions": [ { "ETag": "\"acd8a242d5b76bf7716fe4e7018864c1\"", "Size": 102400, "StorageClass": "STANDARD", "Key": "object1", "VersionId": "3938333335303336323839313537393939393939524730303120203232382e3832373832303835342e3234", "IsLatest": false, "LastModified": "2022-10-05T09:55:10.841000+00:00", "Owner": { "DisplayName": "QUALIF_LXLEGUEN", "ID": "44f9cfd39fe76487c5213ec20c4f6a5545ef9e52d1cbe4ca0e38f87b9d2acdea" } } ], "DeleteMarkers": [ { "Owner": { "DisplayName": "QUALIF_LXLEGUEN", "ID": "44f9cfd39fe76487c5213ec20c4f6a5545ef9e52d1cbe4ca0e38f87b9d2acdea" }, "Key": "object1", "VersionId": "3938333335303336323336323436393939393939524730303120203232382e3832373832323131332e3235", "IsLatest": true, "LastModified": "2022-10-05T09:56:03.753000+00:00" } ] } [root@mytest ~]# aws --endpoint-url https://s3-region01.cloudavenue.orange-business.com s3api list-object-versions --bucket mydemobucket An error occurred (404) when calling the HeadObject operation: Not Found
2. cancel the DELETE by deleting a delete marker (the initial object version becomes current)
[root@mytest ~]# aws --endpoint-url https://s3-region01.cloudavenue.orange-business.com s3api head-object --bucket mydemobucket --key object13938333335303336323336323436393939393939524730303120203232382e3832373832323131332e3235 { "DeleteMarker": true, "VersionId": "3938333335303336323336323436393939393939524730303120203232382e3832373832323131332e3235" } [root@mytest ~]# aws --endpoint-url https://s3-region01.cloudavenue.orange-business.com s3api list-object-versions --bucket mydemobucket3938333335303336323336323436393939393939524730303120203232382e3832373832323131332e3235 { { "Versions": [ { "ETag": "\"acd8a242d5b76bf7716fe4e7018864c1\"", "Size": 102400, "StorageClass": "STANDARD", "Key": "object1", "VersionId": "3938333335303336323839313537393939393939524730303120203232382e3832373832303835342e3234", "IsLatest": true, "LastModified": "2022-10-05T09:55:10.841000+00:00", "Owner": { "DisplayName": "QUALIF_LXLEGUEN", "ID": "44f9cfd39fe76487c5213ec20c4f6a5545ef9e52d1cbe4ca0e38f87b9d2acdea" } } ] } } [root@mytest ~]# aws --endpoint-url https://s3-region01.cloudavenue.orange-business.com s3api head-object --bucket mydemobucket --key object1 { "AcceptRanges": "bytes", "LastModified": "2022-10-05T09:55:10+00:00", "ContentLength": 102400, "ETag": "\"acd8a242d5b76bf7716fe4e7018864c1\"", "VersionId": "3938333335303336323839313537393939393939524730303120203232382e3832373832303835342e3234", "Metadata": {} }
Suspend versioning
[root@mytest ~]# aws --endpoint-url https://s3-region01.cloudavenue.orange-business.com s3api put-bucket-versioning --bucket mydemobucket --versioning-configuration Status=Suspended
Any existing object’s version and delete marker are kept intact.
Once versioning is suspended, version id will always be set to null
.
PUT adds a new object’s version with version id null
.
The object is overwritten if it already exists with version id null
.
[root@mytest ~]# aws --endpoint-url https://s3-region01.cloudavenue.orange-business.com s3api put-object --bucket mydemobucket --key object1 --body ./1mb_file.random { "ETag": "\"2bd0a7886355c628b78b0052673d7789\"" } [root@mytest ~]# aws --endpoint-url https://s3-region01.cloudavenue.orange-business.com s3api list-object-versions --bucket mydemobucket { "Versions": [ { "ETag": "\"2bd0a7886355c628b78b0052673d7789\"", "Size": 1048576, "StorageClass": "STANDARD", "Key": "object1", "VersionId": "null", "IsLatest": true, "LastModified": "2022-10-10T09:46:00.244000+00:00", "Owner": { "DisplayName": "QUALIF_LXLEGUEN", "ID": "44f9cfd39fe76487c5213ec20c4f6a5545ef9e52d1cbe4ca0e38f87b9d2acdea" } }, { "ETag": "\"acd8a242d5b76bf7716fe4e7018864c1\"", "Size": 102400, "StorageClass": "STANDARD", "Key": "object1", "VersionId": "3938333335303336323839313537393939393939524730303120203232382e3832373832303835342e3234", "IsLatest": false, "LastModified": "2022-10-05T09:55:10.841000+00:00", "Owner": { "DisplayName": "QUALIF_LXLEGUEN", "ID": "44f9cfd39fe76487c5213ec20c4f6a5545ef9e52d1cbe4ca0e38f87b9d2acdea" } } ] }
DELETE adds a new delete marker with version id null
.
The current object’s version with version id null is deleted.
[root@mytest ~]# aws --endpoint-url https://s3-region01.cloudavenue.orange-business.com s3api delete-object --bucket mydemobucket --key object1 { "DeleteMarker": true, "VersionId": "null" } [root@mytest ~]# aws --endpoint-url https://s3-region01.cloudavenue.orange-business.com s3api list-object-versions --bucket mydemobucket { "Versions": [ { "ETag": "\"acd8a242d5b76bf7716fe4e7018864c1\"", "Size": 102400, "StorageClass": "STANDARD", "Key": "object1", "VersionId": "3938333335303336323839313537393939393939524730303120203232382e3832373832303835342e3234", "IsLatest": false, "LastModified": "2022-10-05T09:55:10.841000+00:00", "Owner": { "DisplayName": "QUALIF_LXLEGUEN", "ID": "44f9cfd39fe76487c5213ec20c4f6a5545ef9e52d1cbe4ca0e38f87b9d2acdea" } } ], "DeleteMarkers": [ { "Owner": { "DisplayName": "QUALIF_LXLEGUEN", "ID": "44f9cfd39fe76487c5213ec20c4f6a5545ef9e52d1cbe4ca0e38f87b9d2acdea" }, "Key": "object1", "VersionId": "null", "IsLatest": true, "LastModified": "2022-10-10T09:46:54.579000+00:00" } ] }
When an object is deleted, a PUT (same object) automatically removes the delete marker.
[root@mytest ~]# aws --endpoint-url https://s3-region01.cloudavenue.orange-business.com s3api put-object --bucket mydemobucket --key object1 --body ./64mb_file.random { "ETag": "\"ee15117947eab82ac3c3210a94392056\"" } [root@mytest ~]# aws --endpoint-url https://s3-region01.cloudavenue.orange-business.com s3api list-object-versions --bucket mydemobucket { "Versions": [ { "ETag": "\"ee15117947eab82ac3c3210a94392056\"", "Size": 67108864, "StorageClass": "STANDARD", "Key": "object1", "VersionId": "null", "IsLatest": true, "LastModified": "2022-10-10T09:48:39.779000+00:00", "Owner": { "DisplayName": "QUALIF_LXLEGUEN", "ID": "44f9cfd39fe76487c5213ec20c4f6a5545ef9e52d1cbe4ca0e38f87b9d2acdea" } }, { "ETag": "\"acd8a242d5b76bf7716fe4e7018864c1\"", "Size": 102400, "StorageClass": "STANDARD", "Key": "object1", "VersionId": "3938333335303336323839313537393939393939524730303120203232382e3832373832303835342e3234", "IsLatest": false, "LastModified": "2022-10-05T09:55:10.841000+00:00", "Owner": { "DisplayName": "QUALIF_LXLEGUEN", "ID": "44f9cfd39fe76487c5213ec20c4f6a5545ef9e52d1cbe4ca0e38f87b9d2acdea" } } ] }
Best practices
About security
Never use a root Access Key
With a root AK, you can disable versioning and delete all object’s versions (including delete markers).
Restrict permissions
For everyday use (PUT objects in a bucket), you should apply a policy removing (deny) the following permissions :
s3:PutBucketVersioning (to prevent versioning change)
s3:DeleteObjectVersion (to prevent any delete of object’s version and delete marker)
s3:PutLifeCycleConfiguration (to prevent deleting with a lifecycle configuration)
Usage management
When versioning is enabled on a bucket, it is highly recommended to setup a lifecycle configuration .
It’s an easy way to keep control of your storage usage .
A bucket’s lifecycle configuration allows to automatically expire (delete):
non current object’s versions
obsolete delete markers (a delete marker with zero non current object’s version, useless because there’s no more data)
current object’s versions