S3 buckets with no lifecycle configuration, so cold objects stay in S3 Standard indefinitely
What does ZopNight detect here?
ZopNight flags S3 buckets that have no lifecycle configuration at all, meaning nothing moves ageing objects out of S3 Standard. The saving would be the cold Standard data multiplied by the Standard to Standard-IA rate gap, $0.023 versus $0.0125 per GB-month in us-east-1, and ZopNight waits for a per-bucket cold-data measure before showing one.
Signal and threshold
| Field | Value |
|---|---|
| Rule IDs | RC-072 |
| Category | rightsizing |
| Severity | low |
| Metric | none — pure configuration read |
| Threshold | no lifecycle configuration and measured cold Standard data |
| Source | ZopNight |
| Permissions used | s3:ListAllMyBuckets · s3:GetLifecycleConfiguration · cloudwatch:GetMetricStatistics |
Where it applies
Without a lifecycle rule, S3 never moves or deletes anything
S3 does not tier objects on its own. An S3 Lifecycle configuration is the set of rules that transitions objects to cheaper storage classes or expires them after a number of days. A bucket without one keeps every object in the class it was written to, usually S3 Standard, until someone deletes it by hand.
The rate gap is large. AWS’s price list for US East (N. Virginia) shows S3 Standard at $0.023 per GB for the first 50 TB each month and S3 Standard-IA at $0.0125, with S3 Glacier Flexible Retrieval at $0.0036 and S3 Glacier Deep Archive at $0.00099.
Finding buckets with no lifecycle configuration
get-bucket-lifecycle-configuration returns an error for a bucket that has none, so a loop can list
them:
for b in $(aws s3api list-buckets --query 'Buckets[].Name' --output text); do aws s3api get-bucket-lifecycle-configuration --bucket "$b" >/dev/null 2>&1 || echo "$b"doneFor each result, check how much sits in Standard with the free daily storage metric:
aws cloudwatch get-metric-statistics --namespace AWS/S3 --metric-name BucketSizeBytes \ --dimensions Name=BucketName,Value=my-bucket Name=StorageType,Value=StandardStorage \ --start-time 2026-09-22T00:00:00Z --end-time 2026-09-25T00:00:00Z \ --period 86400 --statistics AverageSignals ZopNight needs for this bucket
- ZopNight has confirmed the bucket has no lifecycle policy. If it cannot tell, it assumes nothing.
- The bucket has a known monthly cost.
- ZopNight has current Standard and Standard-IA storage rates.
- It has a measured amount of cold data in Standard, meaning data that is old and rarely read.
What keeps the finding hidden today
Total bucket size is not enough: it cannot tell you how much of the data is cold. ZopNight does not yet collect that per-bucket cold-data figure, so the rule raises nothing on any bucket until it does. The older approach of claiming a fixed share of the bucket bill has been removed, because a lifecycle rule only saves money on data that actually qualifies to move.
The transition saving
saving = cold Standard GB x (Standard rate - Standard-IA rate)ZopNight prices only the Standard-IA step. Moving further, to a Glacier class, would save more per GB but adds retrieval fees and minimum storage durations.
Adding a lifecycle configuration
- Decide the ages per prefix: for example Standard-IA after 30 days, a Glacier class after 90, and expiry after 365 where data may be deleted.
- Write the rules and apply them:
aws s3api put-bucket-lifecycle-configuration --bucket my-bucket \ --lifecycle-configuration file://lifecycle.json- Keep small objects in mind. By default S3 does not transition objects under 128 KB, per the transition considerations, and Standard-IA bills smaller objects as 128 KB, per the storage class guide.