Enforce WORM Compliance on GCS with Bucket Lock Retention and Versioned Soft-Delete
Enable GCS Bucket Lock with a locked default retention period and versioning to enforce WORM compliance. Covers prerequisites, gsutil steps to set and lock retention, validation via audit logs, and recovery limits when a policy is locked.
23 Aug 2026, 23:00 UTC

The problem: you need immutable audit storage that cannot be deleted on demand
Production audit logs and financial records often require Write Once Read Many, WORM, guarantees. In Cloud Storage that means a bucket where objects cannot be deleted or overwritten before a retention period expires, even by an administrator with broad IAM. Bucket Lock provides compliance-grade immutability by locking a default retention period at the bucket level. Once locked the period is append-only.
Versioning works with Bucket Lock to give you controlled soft-delete. Deleting an object creates a delete marker, but the previous versions remain until retention expires. That combination satisfies auditors while keeping normal write operations.
Desired outcome
A production bucket with:
- Object versioning enabled
- A default retention period set and locked
- Delete and overwrite attempts rejected with 403 during retention
- Validation steps you can run without touching production data
Prerequisites
Bucket Lock is supported on standard storage classes in multi-region and regional locations. It is not available on Nearline, Coldline, Archive, or buckets created with specific legacy configurations.
- A GCS bucket in a supported location. Use the bucket name as a placeholder, e.g. gs://my-prod-audit-logs.
- An identity with roles/storage.admin for bucket configuration and roles/storage.objectAdmin for object operations. Bucket Lock changes require storage.buckets.update.
- Versioning must be enabled before retention can be locked. Enabling versioning later on a bucket with existing objects is allowed, but retention lock requires versioning to be on at lock time.
- Understand that retention is append-only. Once locked, the default retention period can only be increased, never decreased, and the lock cannot be removed.
Focused procedure
1. Enable versioning
Run from a workstation with gsutil authenticated via gcloud auth application-default login. Required permission: storage.buckets.update.
gsutil versioning set on gs://my-prod-audit-logs
Risk: versioning increases storage cost because prior versions are retained. Plan lifecycle rules for non-current versions after retention expires.
2. Set a default retention period
Retention is expressed in days. Object-level retention can be longer than the bucket default but never shorter.
gsutil retention set 2555d gs://my-prod-audit-logs
This sets a default retention of 2555 days, approximately 7 years, for all new objects. Existing objects are not retroactively covered unless object-level retention is applied.
3. Lock the retention policy
Locking makes the retention period immutable. Confirm the period first.
gsutil retention get gs://my-prod-audit-logs
Then lock:
gsutil retention lock gs://my-prod-audit-logs
Required permission: storage.buckets.update. Once locked, any attempt to reduce the period or unlock returns an error.
4. Optional object-level retention
For specific objects you can set a longer retention. This cannot be shorter than the bucket default.
gsutil retention set 3650d gs://my-prod-audit-logs/sensitive/report-2025.parquet
Object-level retention is useful for records with different compliance windows.
Expected checks
Verify configuration
- Versioning: gsutil versioning get gs://my-prod-audit-logs should show Enabled: True.
- Retention settings: gsutil retention get gs://my-prod-audit-logs returns the effective period and lock state.
- Console check: Cloud Console > Storage > Buckets > my-prod-audit-logs > Configuration > Bucket Lock shows retention period and Locked status.
Validate enforcement
Attempt a delete on a newly written object within the retention window using an account with storage.objects.delete. The operation should be rejected with 403 Forbidden due to retention.
Review Cloud Audit Logs for storage.googleapis.com data access events. Look for storage.objects.delete and storage.objects.update actions with status PERMISSION_DENIED during the retention window. This confirms policy enforcement without risking production data.
Confirm soft-delete behavior
With versioning on, a delete creates a delete marker. List versions with gsutil ls -a gs://my-prod-audit-logs/object.txt to see prior generations remain accessible until retention expires.
Limitations and recovery options
Bucket Lock is append-only. You cannot shorten a locked retention period or remove the lock. Google Support cannot unlock a locked policy.
If you lock with an incorrect period, the only remediation is to create a new bucket with the correct policy and copy data into it. Copying resets object creation time, so plan for compliance impact.
Retention applies to deletion and overwrite. Objects can still be read by principals with storage.objects.get. Changing storage class is allowed unless it would reduce retention guarantees.
Accidental lock can be mitigated operationally by:
- Testing the exact retention value in a non-production bucket first
- Using a dry-run validation step with gsutil retention get before lock
- Documenting the locked period in change management
When retention finally expires, objects and their versions become eligible for deletion. Combine Bucket Lock with a lifecycle rule to delete non-current versions after retention to control cost.
Practical notes
Do not enable Bucket Lock on a bucket that already requires frequent deletions within the chosen window. Soft-delete via versioning preserves data but increases cost.
Object-level retention longer than bucket default is allowed. Shorter is rejected. This asymmetry can cause unexpected storage growth if teams set long object retention without lifecycle cleanup.
Keep the bucket owner separate from routine writers to reduce risk of accidental bucket configuration changes. Use IAM Conditions where possible to limit who can set retention.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.