S3 Bucket Lifecycle Configuration
Overview
This check verifies that your S3 buckets have lifecycle configuration enabled. Lifecycle rules automatically manage your objects by transitioning them to cheaper storage classes or deleting them after a specified period.
Risk
Without lifecycle policies, S3 objects stay forever, which leads to:
- Higher storage costs from accumulating old data
- Security exposure if sensitive data is retained longer than needed
- Compliance violations if your organization has mandatory data deletion timelines
- Operational complexity from unmanaged log files and object versions piling up
Remediation Steps
Prerequisites
You need permission to modify S3 bucket settings. Specifically, you need the s3:PutLifecycleConfiguration permission.
AWS Console Method
- Open the Amazon S3 console
- Click on the bucket you want to configure
- Select the Management tab
- In the Lifecycle rules section, click Create lifecycle rule
- Enter a rule name (e.g., "Cleanup-old-data")
- Under Choose a rule scope, select Apply to all objects in the bucket (or filter by prefix/tags if preferred)
- Check Acknowledge that this rule applies to all objects
- Under Lifecycle rule actions, select the actions you want:
- Transition current versions of objects between storage classes - move objects to cheaper storage
- Expire current versions of objects - delete objects after a set time
- Delete expired object delete markers or incomplete multipart uploads - clean up partial uploads
- Configure the timing for each selected action (e.g., transition to Glacier after 90 days)
- Click Create rule
AWS CLI (optional)
Basic lifecycle rule to clean up incomplete multipart uploads:
aws s3api put-bucket-lifecycle-configuration \
--bucket <your-bucket-name> \
--region us-east-1 \
--lifecycle-configuration '{
"Rules": [
{
"ID": "CleanupIncompleteMultipartUploads",
"Status": "Enabled",
"Filter": {
"Prefix": ""
},
"AbortIncompleteMultipartUpload": {
"DaysAfterInitiation": 7
}
}
]
}'
Comprehensive lifecycle rule with transitions and expiration:
aws s3api put-bucket-lifecycle-configuration \
--bucket <your-bucket-name> \
--region us-east-1 \
--lifecycle-configuration '{
"Rules": [
{
"ID": "TransitionAndExpire",
"Status": "Enabled",
"Filter": {
"Prefix": ""
},
"Transitions": [
{
"Days": 30,
"StorageClass": "STANDARD_IA"
},
{
"Days": 90,
"StorageClass": "GLACIER"
}
],
"Expiration": {
"Days": 365
}
},
{
"ID": "CleanupMultipartUploads",
"Status": "Enabled",
"Filter": {
"Prefix": ""
},
"AbortIncompleteMultipartUpload": {
"DaysAfterInitiation": 7
}
}
]
}'
Replace <your-bucket-name> with your actual bucket name.
CloudFormation (optional)
AWSTemplateFormatVersion: '2010-09-09'
Description: S3 Bucket with Lifecycle Configuration
Resources:
S3BucketWithLifecycle:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub 'example-bucket-${AWS::AccountId}'
LifecycleConfiguration:
Rules:
- Id: CleanupIncompleteMultipartUploads
Status: Enabled
AbortIncompleteMultipartUpload:
DaysAfterInitiation: 7
- Id: TransitionToInfrequentAccess
Status: Enabled
Transitions:
- StorageClass: STANDARD_IA
TransitionInDays: 30
- Id: TransitionToGlacierAndExpire
Status: Enabled
Transitions:
- StorageClass: GLACIER
TransitionInDays: 90
ExpirationInDays: 365
Outputs:
BucketName:
Description: Name of the S3 bucket with lifecycle configuration
Value: !Ref S3BucketWithLifecycle
Deploy with:
aws cloudformation deploy \
--template-file template.yaml \
--stack-name s3-lifecycle-bucket \
--region us-east-1
Terraform (optional)
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = "us-east-1"
}
resource "aws_s3_bucket" "example" {
bucket = "example-bucket-with-lifecycle"
}
resource "aws_s3_bucket_lifecycle_configuration" "example" {
bucket = aws_s3_bucket.example.id
rule {
id = "cleanup-incomplete-multipart-uploads"
status = "Enabled"
filter {
prefix = ""
}
abort_incomplete_multipart_upload {
days_after_initiation = 7
}
}
rule {
id = "transition-to-infrequent-access"
status = "Enabled"
filter {
prefix = ""
}
transition {
days = 30
storage_class = "STANDARD_IA"
}
}
rule {
id = "transition-to-glacier-and-expire"
status = "Enabled"
filter {
prefix = ""
}
transition {
days = 90
storage_class = "GLACIER"
}
expiration {
days = 365
}
}
}
Apply with:
terraform init
terraform plan
terraform apply
Verification
After configuring lifecycle rules, verify they are in place:
- In the S3 console, go to your bucket and select the Management tab
- You should see your lifecycle rules listed under Lifecycle rules
- Confirm each rule shows Enabled status
CLI verification
aws s3api get-bucket-lifecycle-configuration \
--bucket <your-bucket-name> \
--region us-east-1
This returns the current lifecycle configuration. If no rules exist, you will see an error: The lifecycle configuration does not exist.
Additional Resources
- AWS S3 Object Lifecycle Management
- S3 Storage Classes
- S3 Lifecycle Configuration Elements
- Prowler Check Documentation
Notes
- Overwrite behavior: Setting a new lifecycle configuration replaces any existing one. If you have existing rules you want to keep, include them in your new configuration.
- Minimum object size: Objects smaller than 128 KB cannot be transitioned to STANDARD_IA or ONEZONE_IA storage classes.
- Transition timing: There is a minimum 30-day period before objects can transition from STANDARD to STANDARD_IA or ONEZONE_IA.
- Cost considerations: While lifecycle rules reduce storage costs long-term, retrieval from Glacier storage incurs charges. Plan your transitions based on actual access patterns.
- Versioned buckets: For versioned buckets, you can create separate rules for current and noncurrent object versions.