DEV Community

Muskan _zop
Muskan _zop

Posted on

What Config Drift Costs You: CloudWatch Log Retention, S3 Lifecycle Policies and RDS Multi-AZ, Priced

Config drift usually gets discussed as a correctness problem: the running state no longer matches the intended one. But three specific drifts are money problems first, and they share a shape: a default nobody chose, set at provision time, growing silently ever since. None of them shows up as an incident. All of them show up on the bill, unlabeled.

Here they are, priced, with the fix for each.

CloudWatch log groups that never expire

The default retention for a CloudWatch log group is never expire. Not 90 days, not a year: forever. Every log group created without an explicit retention setting accumulates at $0.03 per GB-month of storage, on top of the $0.50 per GB you already paid at ingestion.

The math compounds quietly. A service logging 5 GB a day into a no-retention group holds about 3.6 TB after two years: roughly $110 a month in pure storage, growing about $4.50 more every month, for logs nobody has ever queried past week one. Multiply by the forty log groups a typical account accumulates, and drift becomes a line item.

Two commands end it. Find the offenders:

aws logs describe-log-groups \
  --query 'logGroups[?retentionInDays==null].[logGroupName, storedBytes]' --output table
Enter fullscreen mode Exit fullscreen mode

Then set retention (30 to 90 days covers most operational needs; compliance logs belong in S3 with lifecycle rules, not in CloudWatch at 6x the storage price): aws logs put-retention-policy --log-group-name <name> --retention-in-days 90. Existing data past the new retention ages out on its own. While you're in there, the sibling drift: debug-level logging left on after an incident multiplies the ingest bill, and ingest, unlike storage, can't be cleaned up retroactively.

S3 buckets with no lifecycle policy

Standard storage costs $0.023 per GB-month. Infrequent Access costs $0.0125, Glacier Instant Retrieval $0.004, and Deep Archive $0.00099, 23 times cheaper than Standard. A bucket without a lifecycle policy keeps everything in Standard forever, which for logs, backups, exports, and build artifacts means paying the hot price for data whose access probability dropped to near zero after thirty days.

Priced: 10 TB of aging logs in Standard is $230 a month. The same bytes in Deep Archive: about $10. Per bucket, per year, that's a $2,600 difference for one policy document.

The honest fine print, because lifecycle rules have teeth: transitions bill per 1,000 objects (millions of tiny objects can make a transition cost more than it saves; aggregate small files first or filter by size), each colder tier has a minimum storage duration (30 days in IA, 90 in Glacier tiers, 180 in Deep Archive) so churning data doesn't belong there, and retrieval from deep tiers costs time and money, which is fine for backups and audit logs and wrong for anything an application reads. When the access pattern is genuinely unknown, Intelligent-Tiering automates the decision for $0.0025 per 1,000 objects monitored, and its main failure mode is being forgotten on buckets full of tiny objects.

The audit is one loop: list buckets, check get-bucket-lifecycle-configuration, and every bucket that errors with "no lifecycle configuration" and holds logs or backups is drift with a dollar sign.

Multi-AZ in the wrong places, both directions

RDS Multi-AZ doubles the instance and storage cost, exactly. That fact cuts both ways, and both directions are drift.

Production missing Multi-AZ is risk drift: a single-AZ prod database is one AZ event away from an outage that costs more than a decade of the standby's price. The check, run against your list of production identifiers:

aws rds describe-db-instances \
  --query 'DBInstances[?MultiAZ==`false`].DBInstanceIdentifier'
Enter fullscreen mode Exit fullscreen mode

Non-production running Multi-AZ is cost drift, and it's usually a copy-paste artifact: someone cloned the prod Terraform module for staging and the standby came along. A db.m5.large at about $125 a month becomes $250; a dev environment with four such databases is quietly paying $6,000 a year for high availability that protects test data.

The same copy-paste family includes backup retention set to 35 days on throwaway databases and snapshot schedules that never met a deletion policy. The principle across all of it: availability settings should be a deliberate per-environment decision, and any environment where you can't name who chose the setting is running on drift.

The meta-point: drift is a flow

Fix all three today and they return, because the source of drift is provisioning behavior, not the current inventory: new log groups still default to never-expire, new buckets still ship without lifecycle rules, and the next cloned module still carries prod settings into dev. The durable fixes live at provision time (IaC modules with retention and lifecycle baked in, and a linter that rejects a prod-tier setting in a non-prod path) plus a periodic re-audit, because the fleet you audited is not the fleet you'll have in six months.

FAQ

What is the default CloudWatch log retention?

Never expire. Any log group created without an explicit retention policy keeps its data forever at $0.03 per GB-month, on top of the one-time $0.50 per GB ingestion charge. Setting retention (30 to 90 days for operational logs) is one command per group and existing over-age data ages out automatically.

Do S3 lifecycle policies save money on any bucket?

Not automatically. They pay off on data with a decaying access pattern (logs, backups, artifacts) and can backfire on buckets with millions of tiny objects (per-object transition fees) or short-lived data (minimum storage durations of 30 to 180 days in colder tiers). Check object count and churn before writing the rule; use size filters or aggregate small files first.

Is Intelligent-Tiering better than a lifecycle policy?

It's the right default when access patterns are unknown or mixed: it moves objects automatically for a $0.0025 per 1,000 objects monitoring fee with no retrieval charges between the frequent and infrequent tiers. A hand-written lifecycle rule beats it when the pattern is predictable, and neither replaces deleting data with no retention requirement at all.

How much extra does RDS Multi-AZ cost?

Double, exactly: the standby replica bills the same instance and storage rate as the primary. That's cheap insurance for production and pure waste for dev and staging, which is why the audit runs both directions: single-AZ production databases (risk) and Multi-AZ non-production ones (cost).

How do I keep these settings from drifting again?

Move the defaults into provisioning: IaC modules that set log retention, bucket lifecycle, and per-environment availability explicitly, plus a policy check that fails a plan carrying prod-tier settings into non-prod paths. Then re-audit quarterly, because drift is generated by ongoing provisioning, not by the resources you already fixed.

Top comments (0)