S3 Bucket Object Lock
Overview
This check verifies that your Amazon S3 buckets have Object Lock enabled. Object Lock applies Write-Once-Read-Many (WORM) protection to your data, preventing objects from being deleted or overwritten for a specified retention period.
Risk
Without Object Lock, your S3 objects can be deleted or modified at any time. This creates several risks:
- Ransomware attacks can delete your backups, leaving you unable to recover
- Accidental deletions by users or automated processes cannot be undone
- Insider threats could tamper with or destroy critical data
- Compliance failures if regulations require immutable data retention (HIPAA, SEC 17a-4, etc.)
Remediation Steps
Prerequisites
- AWS account access with permissions to modify S3 bucket settings
- The bucket must have versioning enabled (Object Lock requires it)
Important: Object Lock can only be enabled when creating a new bucket. For existing buckets without Object Lock, you must create a new bucket with Object Lock enabled and migrate your data.
AWS Console Method
For New Buckets
- Open the Amazon S3 console
- Click Create bucket
- Enter a unique bucket name
- Under Object Lock, check Enable
- Acknowledge the warning about versioning
- Complete the bucket creation wizard and click Create bucket
- After creation, go to the bucket's Properties tab
- Scroll to Object Lock and click Edit
- Enable Default retention
- Set Mode to Governance (allows users with special permissions to modify) or Compliance (no one can delete, including root)
- Set Retention period (e.g., 1 day, 1 year)
- Click Save changes
For Existing Buckets Without Object Lock
Since Object Lock cannot be added to existing buckets, you must:
- Create a new bucket with Object Lock enabled (steps above)
- Copy objects from the old bucket to the new bucket
- Update applications to use the new bucket
- Delete the old bucket when no longer needed
AWS CLI (optional)
Check if Object Lock is enabled on an existing bucket:
aws s3api get-object-lock-configuration \
--bucket <your-bucket-name> \
--region us-east-1
Create a new bucket with Object Lock enabled:
# Step 1: Create bucket with Object Lock
aws s3api create-bucket \
--bucket <your-new-bucket-name> \
--region us-east-1 \
--object-lock-enabled-for-bucket
# Step 2: Configure Object Lock default retention
aws s3api put-object-lock-configuration \
--bucket <your-new-bucket-name> \
--region us-east-1 \
--object-lock-configuration '{
"ObjectLockEnabled": "Enabled",
"Rule": {
"DefaultRetention": {
"Mode": "GOVERNANCE",
"Days": 1
}
}
}'
Enable Object Lock on an existing bucket (if supported):
As of late 2023, AWS allows enabling Object Lock on existing versioned buckets:
# First, ensure versioning is enabled
aws s3api put-bucket-versioning \
--bucket <your-bucket-name> \
--region us-east-1 \
--versioning-configuration Status=Enabled
# Then enable Object Lock
aws s3api put-object-lock-configuration \
--bucket <your-bucket-name> \
--region us-east-1 \
--object-lock-configuration '{
"ObjectLockEnabled": "Enabled",
"Rule": {
"DefaultRetention": {
"Mode": "GOVERNANCE",
"Days": 1
}
}
}'
Copy objects to the new bucket (if migration is needed):
aws s3 sync s3://<old-bucket-name> s3://<new-bucket-name> --region us-east-1
CloudFormation (optional)
AWSTemplateFormatVersion: '2010-09-09'
Description: S3 Bucket with Object Lock enabled
Parameters:
BucketName:
Type: String
Description: Name for the S3 bucket with Object Lock
RetentionDays:
Type: Number
Default: 1
Description: Default retention period in days
RetentionMode:
Type: String
Default: GOVERNANCE
AllowedValues:
- GOVERNANCE
- COMPLIANCE
Description: Object Lock retention mode
Resources:
S3BucketWithObjectLock:
Type: AWS::S3::Bucket
Properties:
BucketName: !Ref BucketName
ObjectLockEnabled: true
ObjectLockConfiguration:
ObjectLockEnabled: Enabled
Rule:
DefaultRetention:
Mode: !Ref RetentionMode
Days: !Ref RetentionDays
VersioningConfiguration:
Status: Enabled
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
Outputs:
BucketName:
Description: Name of the created bucket
Value: !Ref S3BucketWithObjectLock
BucketArn:
Description: ARN of the created bucket
Value: !GetAtt S3BucketWithObjectLock.Arn
Deploy the stack:
aws cloudformation create-stack \
--stack-name s3-object-lock-bucket \
--template-body file://template.yaml \
--parameters ParameterKey=BucketName,ParameterValue=<your-bucket-name> \
--region us-east-1
Terraform (optional)
terraform {
required_version = ">= 1.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 4.0"
}
}
}
variable "bucket_name" {
description = "Name for the S3 bucket with Object Lock"
type = string
}
variable "retention_days" {
description = "Default retention period in days"
type = number
default = 1
}
variable "retention_mode" {
description = "Object Lock retention mode (GOVERNANCE or COMPLIANCE)"
type = string
default = "GOVERNANCE"
validation {
condition = contains(["GOVERNANCE", "COMPLIANCE"], var.retention_mode)
error_message = "Retention mode must be either GOVERNANCE or COMPLIANCE."
}
}
resource "aws_s3_bucket" "object_lock_bucket" {
bucket = var.bucket_name
object_lock_enabled = true
}
resource "aws_s3_bucket_versioning" "object_lock_bucket" {
bucket = aws_s3_bucket.object_lock_bucket.id
versioning_configuration {
status = "Enabled"
}
}
resource "aws_s3_bucket_object_lock_configuration" "object_lock_bucket" {
bucket = aws_s3_bucket.object_lock_bucket.id
rule {
default_retention {
mode = var.retention_mode
days = var.retention_days
}
}
}
resource "aws_s3_bucket_public_access_block" "object_lock_bucket" {
bucket = aws_s3_bucket.object_lock_bucket.id
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}
output "bucket_name" {
description = "Name of the created bucket"
value = aws_s3_bucket.object_lock_bucket.id
}
output "bucket_arn" {
description = "ARN of the created bucket"
value = aws_s3_bucket.object_lock_bucket.arn
}
Deploy:
terraform init
terraform plan -var="bucket_name=<your-bucket-name>"
terraform apply -var="bucket_name=<your-bucket-name>"
Verification
- Open the S3 console
- Click on your bucket name
- Go to the Properties tab
- Scroll to Object Lock - it should show Enabled with your retention settings
CLI Verification
aws s3api get-object-lock-configuration \
--bucket <your-bucket-name> \
--region us-east-1
Expected output:
{
"ObjectLockConfiguration": {
"ObjectLockEnabled": "Enabled",
"Rule": {
"DefaultRetention": {
"Mode": "GOVERNANCE",
"Days": 1
}
}
}
}
Additional Resources
- Amazon S3 Object Lock Overview
- Configuring S3 Object Lock
- Using S3 Object Lock with Replication
- AWS CLI put-object-lock-configuration Reference
Notes
-
GOVERNANCE vs COMPLIANCE mode: In Governance mode, users with special IAM permissions (
s3:BypassGovernanceRetention) can still delete or modify objects. In Compliance mode, no one can delete objects until the retention period expires - not even the root account. -
Retention period: Choose carefully. In Compliance mode, you cannot shorten the retention period once set. Start with a short period (e.g., 1 day) for testing.
-
Cost considerations: Object Lock itself has no additional cost, but keeping object versions for the retention period increases storage costs.
-
Legal Hold: In addition to retention periods, you can place a Legal Hold on specific objects. This prevents deletion regardless of retention settings until the hold is explicitly removed.
-
Existing objects: Default retention settings only apply to new objects. To protect existing objects, you must apply retention settings to each object individually or use S3 Batch Operations.