S3 Object Lock
Explanation of Object Lock
Object lock makes objects immutable, which means that they can't be encrypted and held for ransom by bad actors.
There are two modes of object lock:
- Governance Mode
- Compliance Mode
In governance mode, objects can be deleted by users who have the
s3:BypassGovernanceRetention permission.
In compliance mode, objects cannot be deleted before a specified "retention date". No user can delete objects that have been locked in this way.
General Format of Commands
The general format of commands that set object lock is as follows:
aws --profile=ceph --endpoint-url <URL> s3api put-object-legal-hold \
--bucket <bucket_name> \
--key <object> \
--version-id <version> \
--legal-hold Status=OFF
Governance Mode
In this procedure, we will create a bucket that has Object Lock enabled in
governance mode, and then attempt to delete it. This procedure will demonstrate
the security of Object Lock in governance mode by demonstrating the
impossibility of deleting the bucket unless the user has the
s3:BypassGovernanceRetention permission.
-
Create a bucket that has Object Lock enabled:
$ aws --endpoint-url=http://xx2.xx.xxx.x s3api create-bucket --bucket test-bucket --object-lock-enabled-for-bucket -
Add the object-lock configuration (this can be "governance" or "compliance", but "governance" is used here):
$ aws --endpoint-url=http://xxx.xx.xxx.x s3api put-object-lock-configuration --bucket test-bucket --object-lock-configuration '{"ObjectLockEnabled":"Enabled","Rule":{"DefaultRetention":{"Mode":"GOVERNANCE","Days":90}}}' -
Add an object to the bucket:
$ aws --endpoint-url=http://xxx.xx.xxx.x s3api put-object --bucket test-bucket --body some-object.png --key some-object.png
{
"ETag": "\"xxx\"",
"VersionId": "xxx"
} -
Now that the object has been created, we will attempt to delete it:
$ aws --endpoint-url=http://xxx.xx.xxx.x s3api delete-object --bucket test-bucket --key some-object.png
{
"DeleteMarker": true,
"VersionId": "xxx"
}
$ aws --endpoint-url=http://xxx.xx.xxx.x s3api delete-object --bucket test-bucket --key some-object.png --version-id xxx
An error occurred (AccessDenied) when calling the DeleteObject operation: forbidden by object lock
$ aws --endpoint-url=http://xxx.xx.xxx.x s3api get-object-retention --bucket test-bucket --key some-object.png --version-id xxx
{
"Retention": {
"Mode": "GOVERNANCE",
"RetainUntilDate": "2026-12-31T23:59:00.000000+00:00"
}
}This demonstrates that the object cannot be deleted.
-
Now we demonstrate that the user
testis able to bypass governance mode:$ aws --endpoint-url=http://xxx.xx.xxx.x s3api delete-object --bucket test-bucket --key some-object.png --version-id xxx --bypass-governance-retention
{
"VersionId": "xxx"
}
$ aws --endpoint-url=http://xxx.xx.xxx.x s3api list-object-versions --bucket test-bucket {
"DeleteMarkers": [
{
"Owner": {
"DisplayName": "test",
"ID": "test"
},
"Key": "some-object.png",
"VersionId": "xxx",
"IsLatest": true,
"LastModified": "2023-01-01T12:00:00.000000+00:00"
}
]
}This demonstrates that the user
testis able to bypass the restrictions set in governance mode. -
Now we will demonstrate that a user cannot bypass the restrictions set in governance mode. Apply the following policy, which removes the
s3:BypassGovernanceRetentionpermission from all users including thetestuser:{
"Version": "2026-01-01",
"Statement": [
{
"Effect": "Deny",
"Principal": {
"AWS": [
"*"
]
},
"Action": "s3:BypassGovernanceRetention",
"Resource": "*"
}
]
} -
Attempt to use the
s3api delete-objectcommand on the bucket calledtest-bucket:$ aws --endpoint-url=http://xxx.xx.xxx.x s3api delete-object --bucket test-bucket --key some-object.png --version-id a0a0aa0a0aaaaaaa.0aaa0a0.0aaaa0 --bypass-governance-retention
An error occurred (AccessDenied) when calling the DeleteObject operation: forbidden by object lockThe bucket has been protected from deletion because
s3:BypassGovernanceRetentionhas been removed.
Compliance Mode
In this procedure, we will create a bucket that has Object Lock enabled in compliance mode, then attempt to delete it, then attempt to change the retention period that has been set. This procedure will demonstrate the security of Object Lock in compliance mode by demonstrating the impossibility of deleting the bucket and then demonstrating the impossibility of reducing the length of the retention period. Note that it is possible to extend the length of the compliance period.
-
Create a bucket that has Object Lock enabled:
$ aws --endpoint-url=http://xxx.xx.xxx.x s3api create-bucket \
--bucket test-bucket --object-lock-enabled-for-bucket -
Add the object-lock configuration (this can be "governance" or "compliance", but "compliance" is used here). In this example the Object Lock is set for ninety (90) days:
$ aws --endpoint-url=http://xxx.xx.xxx.x s3api put-object-lock-configuration --bucket test-bucket \
--object-lock-configuration \
'{"ObjectLockEnabled":"Enabled","Rule":{"DefaultRetention":{"Mode":"COMPLIANCE","Days":90}}}' -
Add an object to the bucket:
$ aws --endpoint-url=http://xxx.xx.xxx.x s3api put-object --bucket test-bucket \
--body some-object.png --key some-object.png
{
"ETag": "\"xxx\"",
"VersionId": "xxx"
} -
Run the following command with the
get-object-retentioncommand to ensure that the object's retention mode is set toCOMPLIANCE:$ aws --endpoint-url=http://xxx.xx.xxx.x s3api get-object-retention --bucket test-bucket \
--key some-object.png
{
"Retention": {
"Mode": "COMPLIANCE",
"RetainUntilDate": "2026-12-31T23:59:59.000000+00:00"
}
} -
Attempt to delete the object. In this example, we attempt to delete the object without specifying the version ID:
$ aws --endpoint-url=http://xxx.xx.xxx.x s3api delete-object --bucket test-bucket --key some-object.png
{
"DeleteMarker": true,
"VersionId": "xxx"
} -
Use the
list-object-versionscommand to see whether the delete marker has been set:$ aws --endpoint-url=http://172.31.117.5 s3api list-object-versions --bucket test-bucket
{
"Versions": [
{
"ETag": "\"xxx\"",
"Size": 10000000,
"StorageClass": "STANDARD",
"Key": "some-object.png",
"VersionId": "xxx",
"IsLatest": false,
"LastModified": "2026-06-01T12:00:00.000000+00:00",
"Owner": {
"DisplayName": "test",
"ID": "test"
}
}
],
"DeleteMarkers": [
{
"Owner": {
"DisplayName": "test",
"ID": "test"
},
"Key": "some-object.png",
"VersionId": "OsXsNSWZe2oLisQ4.kEeDo1xjwklui0",
"IsLatest": true,
"LastModified": "2026-06-01T12:00:00.000000+00:00"
}
]
} -
Attempt to delete the object again by using the
delete-objectcommand and specifying the version ID:$ aws --endpoint-url=http://xxx.xx.xxx.x s3api delete-object \
--bucket test-bucket --key some-object.png \
--version-id aaaaaa0aaa00a0aasaaa0aa0aaa0aaa
An error occurred (AccessDenied) when calling the DeleteObject operation:
forbidden by object lock -
The deletion of the object is forbidden by the object lock that was put in place earlier in this procedure. Now we will attempt to remove that object lock (to demonstrate that it cannot be removed under these conditions):
$ aws --endpoint-url=http://xxx.xx.xxx.x \
s3api put-object-retention --bucket test-bucket --key some-object.png \
--version-id xxx \
--retention '{ "Mode": "GOVERNANCE", "RetainUntilDate": "2026-12-31T23:59:59.000000+00:00" }'
An error occurred (AccessDenied) when calling the PutObjectRetention operation: can't change retention
mode from COMPLIANCE to GOVERNANCE -
Now we will attempt to reduce the duration of the retention period (to demonstrate that it cannot be reduced under these conditions):
$ aws --endpoint-url=http://xxx.xx.xxx.x s3api put-object-retention \
--bucket test-bucket --key some-object.png \
--version-id aaaaaa0aaa00a0aasaaa0aa0aaa0aaa \
--retention '{ "Mode": "COMPLIANCE", "RetainUntilDate": "2026-02-01T00:00:00" }'
An error occurred (AccessDenied) when calling the PutObjectRetention
operation: proposed retain-until date shortens an existing retention
period and governance bypass check failedThis demonstrates that compliance mode, once set on an object, makes it impossible to delete that object until the retention date has passed.
-
Although the retention period cannot be reduced in compliance mode, it can be extended:
aws s3api get-object-retention --bucket lock-3 --key hello.txt { "Retention": { "Mode": "COMPLIANCE", "RetainUntilDate": "2026-02-18T17:31:44.520197+00:00" } }
```bash
aws s3api put-object-retention --bucket lock-3 --key hello.txt --version-id u8V-t5ZFAEUh7Tvobo88aSCgwG-pn4R --retention '{ "Mode": "COMPLIANCE", "RetainUntilDate": "2026-03-01"}'
aws s3api get-object-retention --bucket lock-3 --key hello.txt --version-id u8V-t5ZFAEUh7Tvobo88aSCgwG-pn4R { "Retention": { "Mode": "COMPLIANCE", "RetainUntilDate": "2026-03-01T00:00:00+00:00" } }
aws s3api put-object-retention --bucket lock-3 --key hello.txt --version-id u8V-t5ZFAEUh7Tvobo88aSCgwG-pn4R --retention '{ "Mode": "COMPLIANCE", "RetainUntilDate": "2026-02-20"}'
An error occurred (AccessDenied) when calling the PutObjectRetention operation: proposed retain-until date shortens an existing retention period and governance bypass check failed
Legal Hold
Legal hold is a feature of S3 Object Lock that prevents an object version from being overwritten or deleted. Unlike governance mode and compliance mode, which use retention periods, a legal hold has no associated retention period and remains in effect until it is explicitly removed.
Legal hold has only two settings: ON and OFF. This setting will override
the deletion behavior of GOVERNANCE.
Legal holds are useful in situations where objects must be preserved indefinitely for legal or regulatory reasons, such as during litigation or investigations. A legal hold can be applied to an object at any time, regardless of whether the object already has a retention period set.
In this procedure, we will create a bucket that has Object Lock enabled, apply a legal hold to an object, attempt to delete the object, and then remove the legal hold. This procedure will demonstrate how legal holds protect objects from deletion and how they differ from retention-based modes.
-
Create a bucket that has Object Lock enabled:
$ aws --endpoint-url=http://xxx.xx.xxx.x s3api create-bucket \
--bucket test-bucket --object-lock-enabled-for-bucket -
Add an object to the bucket:
$ aws --endpoint-url=http://xxx.xx.xxx.x s3api put-object \
--bucket test-bucket --body some-object.png --key some-object.png
{
"ETag": "\"xxx\"",
"VersionId": "xxx"
} -
Apply a legal hold to the object:
$ aws --endpoint-url=http://xxx.xx.xxx.x s3api put-object-legal-hold \
--bucket test-bucket --key some-object.png \
--legal-hold Status=ON -
Verify that the legal hold has been applied:
$ aws --endpoint-url=http://xxx.xx.xxx.x s3api get-object-legal-hold \
--bucket test-bucket --key some-object.png
{
"LegalHold": {
"Status": "ON"
}
} -
Attempt to delete the object:
$ aws --endpoint-url=http://xxx.xx.xxx.x s3api delete-object \
--bucket test-bucket --key some-object.png \
--version-id xxx
An error occurred (AccessDenied) when calling the DeleteObject operation:
The specified object version is protected by a Legal HoldThis demonstrates that the object cannot be deleted while a legal hold is in place.
-
Remove the legal hold from the object:
$ aws --endpoint-url=http://xxx.xx.xxx.x s3api put-object-legal-hold \
--bucket test-bucket --key some-object.png \
--legal-hold Status=OFF -
Verify that the legal hold has been removed:
$ aws --endpoint-url=http://xxx.xx.xxx.x s3api get-object-legal-hold \
--bucket test-bucket --key some-object.png
{
"LegalHold": {
"Status": "OFF"
}
} -
Now that the legal hold has been removed, attempt to delete the object again:
$ aws --endpoint-url=http://xxx.xx.xxx.x s3api delete-object \
--bucket test-bucket --key some-object.png \
--version-id xxx
{
"VersionId": "xxx"
}This demonstrates that once the legal hold is removed, the object can be deleted (assuming no other retention mode is in effect).
Legal Hold Permissions
To apply or remove a legal hold from objects, users must have the correct permissions. Here is the list of those permissions:
s3:GetBucketObjectLockConfiguration
s3:PutObjectLegalHold
s3:BypassGovernanceRetention
s3:GetBucketObjectLockConfiguration
s3:GetObjectLegalHold
s3:GetObjectRetention
s3:PutBucketObjectLockConfiguration
s3:PutObjectLegalHold
s3:PutObjectRetention
Legal Hold Considerations
- Legal holds work independently of retention modes. An object can have both a legal hold and a retention period applied simultaneously.
- Legal holds apply to specific object versions. If no version is specified, the legal hold is applied to the latest version.
- Unlike governance mode, legal holds cannot be bypassed with special permissions. They must be explicitly removed.
- Legal holds do not have expiration dates. They remain in effect until manually removed.
- S3 Batch Operations can be used to apply or remove legal holds on multiple objects at once.
- See also the AWS CLI Command Reference for "put-object-legal-hold"
Discussion
- https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-lock.html#object-lock-overview This is the documentation for S3 Object Lock.
- https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-lock.html See this document ("Locking objects with Object Lock") for much more information on Object Lock (current as of February 2026).