terraformplatform-engineeringci-cdcost-optimization

Infrastructure test environments: paying to test the infrastructure itself

Testing Terraform means creating real resources, and real resources bill by the minute. A module test suite that provisions databases and load balancers can cost more than the infrastructure it validates. Here is how to test thoroughly without paying for it twice.

The C3X Team··7 min read

Quick answer

Infrastructure tests that apply real resources cost the resource's hourly rate multiplied by test duration multiplied by test frequency. A suite creating a managed database, a load balancer, and a NAT gateway runs about 0.15 dollars an hour, and a 25 minute test executed 200 times a month is roughly 12 dollars, until a failed destroy leaves resources behind. Most of the value comes from static validation and plan assertions that cost nothing, so reserve real applies for the small set of behaviors only a live resource can prove.

Infrastructure code deserves tests, and the most convincing test applies the module and checks what actually exists. That confidence is real, and so is the bill, because every test run provisions billable resources and every failure risks leaving them behind.

The goal is a test pyramid where the expensive layer is small and the cheap layers catch most problems, which is the same structure that works for application testing.

What each layer costs

Test layerCloud costWhat it catches
Format and lintZeroSyntax, style, obvious errors
Validate and policy checksZeroSchema errors, policy violations
Plan assertionsNear zeroWrong attributes, unintended changes
Cost assertions on the planZeroExpensive defaults, cost regressions
Apply and verifyReal resource hoursProvider bugs, runtime behavior
Full environment integrationHighestCross module interactions

The first four layers cost nothing but CI minutes and catch the large majority of defects. The bottom two are where the money is, so their job is to cover only what cannot be proven statically.

The arithmetic of an apply test

A test that creates a small managed database, a load balancer, and a NAT gateway costs roughly 0.15 dollars an hour combined. A 25 minute test is about 0.06 dollars, and 200 runs a month is about 12 dollars, which is trivially affordable.

What breaks that arithmetic is duration and leakage. Provisioning a Multi-AZ database takes 15 minutes before any assertion runs, and if the test times out and the destroy step is skipped, the resources keep billing indefinitely. One leaked database at 60 dollars a month, repeated a few times a week, is how a 12 dollar test suite becomes a 700 dollar line item.

Make cleanup unconditional

Destroy must run whether the test passed, failed, or crashed. Use the CI equivalent of a finally block, never a step that only runs on success. Beyond that, run a scheduled sweeper that deletes anything in the test account tagged for testing and older than a few hours, because CI runners do get killed mid job.

Give infrastructure tests their own account or subscription with a hard budget alarm. Isolation makes the sweeper safe to run aggressively, and it makes the cost of testing visible as its own number instead of hiding inside a shared non-production bill.

Test the cheap things cheaply

A large share of what teams verify with an apply can be verified from the plan. Whether encryption is enabled, whether the right instance class was selected, whether a security group is too open, whether tags are present, all appear in the plan JSON and need no resources at all.

Cost belongs in that set. Running a cost estimate against the plan and asserting that a module's example stays under a threshold catches expensive regressions at zero cloud cost. c3x does this statically with no cloud credentials, which means the assertion runs in the same job as the plan and needs no account access, a natural fit formodule cost estimation.

Shrink what you apply

When a real apply is necessary, use the cheapest configuration that exercises the behavior. Single-AZ instead of Multi-AZ, the smallest instance class, minimal storage, no read replicas, short backup retention. If the module is parameterized properly, this is just a test fixture that passes different values.

Also split the suite. Run static checks and plan assertions on every pull request, and run the apply tests nightly or on demand against the main branch. That cuts apply frequency by an order of magnitude while keeping the fast feedback developers need.

Budget testing as a line item

Infrastructure testing should cost something, and a reasonable target is under 2 percent of the infrastructure it protects. If your test account is spending 800 dollars a month to validate modules that deploy 15,000 dollars of infrastructure, that is fine. If it is spending 800 dollars to validate 3,000, look at leakage first and apply frequency second.

A pyramid with free static checks on every commit, plan and cost assertions in every pull request, a small set of cheap apply tests nightly, and a full integration run weekly gives strong confidence for a bill in the tens of dollars, rather than a test suite that quietly outspends the thing it tests.

FAQ

How much do Terraform apply tests cost?

A suite creating a small managed database, a load balancer, and a NAT gateway runs roughly 0.15 dollars an hour, so a 25 minute test executed 200 times a month is about 12 dollars. The number only breaks when tests leak resources: one leaked database at 60 dollars a month, a few times a week, turns a 12 dollar suite into a 700 dollar line item.

How do I stop infrastructure tests from leaking resources?

Make destroy unconditional, using the CI equivalent of a finally block rather than a step that runs only on success, and add a scheduled sweeper that deletes anything in the test account tagged for testing and older than a few hours. Give infrastructure tests their own account with a hard budget alarm so the sweeper is safe to run aggressively.

What should be tested without applying real resources?

Most things. Encryption settings, instance class selection, overly open security groups, required tags, and unintended changes all appear in the plan JSON and need no resources. Cost belongs there too: asserting that a module example stays under a threshold catches expensive regressions at zero cloud cost, and C3X evaluates the plan statically with no credentials.

How do I reduce the cost of necessary apply tests?

Use the cheapest configuration that exercises the behavior: single-AZ rather than Multi-AZ, the smallest instance class, minimal storage, no read replicas, short backup retention. Then split the suite so static checks and plan assertions run on every pull request while apply tests run nightly or on demand, cutting apply frequency by roughly an order of magnitude.

What is a reasonable budget for infrastructure testing?

Under about 2 percent of the infrastructure it protects. Spending 800 dollars a month to validate modules deploying 15,000 dollars of infrastructure is reasonable. Spending 800 dollars to validate 3,000 suggests a problem, and the first thing to check is leaked resources from failed destroys, followed by how often apply tests run.

What to do next

Assert cost in CI without creating a single resource. C3X evaluates Terraform plans statically. See the quickstart.

Try C3X on your own Terraform

Free and open source. No API key required. One command to install, one command to estimate.