Provisioned DynamoDB tables with auto-scaling switched off
What does ZopNight detect here?
ZopNight flags a provisioned-capacity DynamoDB table only when the discoverer explicitly recorded auto-scaling as disabled. On-demand tables are excluded by a billing-mode gate, because Application Auto Scaling does not exist for them. Remediation is to enable auto-scaling at a 70% target utilization, or to move unpredictable workloads to on-demand.
Signal and threshold
| Field | Value |
|---|---|
| Rule IDs | RC-1515 |
| Category | compliance |
| Severity | medium |
| Metric | none — pure configuration read |
| Source | dynamodb_autoscaling.go |
Where it applies
Why on-demand tables never show up here
Application Auto Scaling is a Provisioned-capacity feature. An on-demand
(PAY_PER_REQUEST) table has no read or write capacity units to register a scalable
target against, so listing scalable targets legitimately returns zero results for every
on-demand table in the account. A naive “no scalable target means auto-scaling is
disabled” test would therefore stamp the entire on-demand fleet as misconfigured in one
sweep. This rule reads the discovered billing mode first and evaluates only tables that
are actually on Provisioned capacity, the only population the recommendation can apply
to.
The two facts a finding rests on
The discoverer records two pieces of provider state for each table: the billing mode
(PROVISIONED or PAY_PER_REQUEST) and an explicit boolean for whether auto-scaling is
enabled, derived from the table’s registered scalable targets. The finding fires only
when the mode resolves to Provisioned and the auto-scaling boolean is present and
false.
Both failure directions cost you. A provisioned table without auto-scaling is either over-provisioned (paying every hour, at the published provisioned-capacity rates, for capacity units the workload never consumes) or under-provisioned, where a traffic increase surfaces as throttled requests instead of a larger bill. Auto-scaling converts that static guess into a tracked target.
Where the rule deliberately abstains
Three situations produce no finding, by design:
- Billing mode was not discovered. Without knowing the capacity mode, “enable auto-scaling” is not an actionable recommendation, so the rule fails closed.
- The table is on-demand. Auto-scaling does not exist for it; there is nothing to enable.
- The auto-scaling attribute is absent. Enrichment is best-effort and can be denied by IAM. An unknown state is never reported as a misconfigured one.
Checking a table from your terminal
aws application-autoscaling describe-scalable-targets \ --service-namespace dynamodb \ --resource-ids table/my-tableAn empty ScalableTargets list on a Provisioned table confirms the finding. The same
empty list on an on-demand table is normal and means nothing, which is exactly why the
billing-mode gate exists.
Choosing between the two fixes
Enabling auto-scaling with a 70% target utilization is the default fix: capacity floats
with demand and the target leaves headroom for bursts. Workloads that are genuinely
unpredictable, with sharp, irregular spikes and long quiet stretches, are better served
by switching the table to on-demand than by auto-scaling chasing a moving target. After either
change, watch ConsumedReadCapacityUnits and ConsumedWriteCapacityUnits, two of the table-level series DynamoDB publishes to CloudWatch, to confirm
capacity now tracks consumption.