Skip to main content
Storage • 2 mins read

Object Lock (WORM)

Object Lock (WORM)

Object Lock makes a version immutable until a date, or until you release a legal hold. Nobody can permanently delete it before then — not you, not an admin, not Hippius. Use it for backups, audit logs, and compliance (S3 WORM).

The API matches the standard S3 Object Lock API. The lock is applied in the storage layer itself, so a locked version cannot be removed by any path before its time.

Versioning is required

Object Lock protects versions, not keys. --object-lock-enabled-for-bucket turns versioning on for you.

Quick start​

aws s3api create-bucket --bucket my-vault --object-lock-enabled-for-bucket \
--endpoint-url https://s3.hippius.com

aws s3api put-object --bucket my-vault --key report.pdf --body report.pdf \
--object-lock-mode GOVERNANCE \
--object-lock-retain-until-date "$(date -u -d '+30 days' +%Y-%m-%dT%H:%M:%SZ)" \
--endpoint-url https://s3.hippius.com

A versioned delete of that object returns AccessDenied until the date.

Retention modes​

ModeWho can remove it earlyUse for
GOVERNANCEBucket owner, with --bypass-governance-retentionAccidents, with an escape hatch
COMPLIANCENobody, until it expiresAbsolute regulatory retention

You can always extend a retention. You cannot shorten a live one.

COMPLIANCE cannot be undone

A ten-year COMPLIANCE object occupies storage — and bills — for ten years. There is no support path to remove it early. Test with a short window first. Prefer GOVERNANCE unless a regulator requires otherwise.

Set retention​

At upload, or later on a version:

aws s3api put-object --bucket my-vault --key q4.csv --body q4.csv \
--object-lock-mode COMPLIANCE \
--object-lock-retain-until-date 2027-01-01T00:00:00Z \
--endpoint-url https://s3.hippius.com

aws s3api put-object-retention --bucket my-vault --key q4.csv \
--retention '{"Mode":"COMPLIANCE","RetainUntilDate":"2027-01-01T00:00:00Z"}' \
--endpoint-url https://s3.hippius.com

aws s3api get-object-retention --bucket my-vault --key q4.csv \
--endpoint-url https://s3.hippius.com

Retain-until dates beyond 10 years (3650 days) are rejected.

An indefinite lock with no expiry. Independent of retention — either one blocks deletion.

aws s3api put-object-legal-hold --bucket my-vault --key evidence.zip \
--legal-hold Status=ON --endpoint-url https://s3.hippius.com

aws s3api put-object-legal-hold --bucket my-vault --key evidence.zip \
--legal-hold Status=OFF --endpoint-url https://s3.hippius.com

Bucket default​

Every new version inherits a duration, resolved to a date at write time. Applies to PUT, multipart, and copy. Per-object headers override it. Years works too.

aws s3api put-object-lock-configuration --bucket my-vault \
--object-lock-configuration '{
"ObjectLockEnabled": "Enabled",
"Rule": {"DefaultRetention": {"Mode": "GOVERNANCE", "Days": 90}}
}' --endpoint-url https://s3.hippius.com

How deletes behave​

RequestOn a locked version
DELETE key?versionId=…403 AccessDenied
DELETE key (no version)Succeeds — writes a delete marker; the locked version stays

Overwrite is allowed: it creates a new version. Bulk DeleteObjects is per-key — a locked key returns AccessDenied and the rest of the batch continues.

Bypass GOVERNANCE​

Owner and --bypass-governance-retention. Either alone is not enough. No effect on COMPLIANCE or a legal hold.

aws s3api delete-object --bucket my-vault --key report.pdf --version-id "$VID" \
--bypass-governance-retention \
--endpoint-url https://s3.hippius.com

Standard S3 gates this on IAM. Hippius has no IAM, so only the bucket owner can bypass.

Enable on an existing bucket​

Versioning first, then Object Lock. No x-amz-bucket-object-lock-token required. Future versions only — existing objects are not locked retroactively.

aws s3api put-bucket-versioning --bucket existing-bucket \
--versioning-configuration Status=Enabled --endpoint-url https://s3.hippius.com

aws s3api put-object-lock-configuration --bucket existing-bucket \
--object-lock-configuration '{"ObjectLockEnabled":"Enabled"}' \
--endpoint-url https://s3.hippius.com

Without versioning this returns 409 InvalidBucketState.

Set lock headers on CreateMultipartUpload, not CompleteMultipartUpload. Read them back with HeadObject (GetObject does not return them). Sending lock headers to a bucket without Object Lock returns 400 InvalidRequest, not a silent drop.

Not supported​

Not supportedWorkaround
Lock headers on CompleteMultipartUploadSet them on CreateMultipartUpload
Lock headers on GetObject responsesUse HeadObject
Suspending versioning on a lock-enabled bucketStandard S3 does not allow it either
S3 Batch OperationsApply per object
Replicating lock stateSet the lock on the destination
POST ObjectPresigned PutObject

Further reading​