Terraform Operations #4 Security and Cost Scanning: PR Guardrails with trivy, checkov, and Infracost
The checks up through #3 asked whether the code was correct. The two checks in this part ask different questions: is it safe, and how much does it cost? Code that opens a security group wide to the internet and code that launches an instance costing hundreds of dollars a month are both syntactically flawless, so they pass every check we have built so far. Catching these two kinds of accidents at the PR stage is the goal of this part.
Security static analysis: trivy and checkov #
An IaC security scanner compares your resource configuration against known risk patterns. There are two leading tools.
- trivy: the unified tool from Aqua, best known as a container scanner. tfsec, which was Terraform-specific, has been merged into trivy — so when a search turns up tfsec material, read it as “this is trivy now.”
- checkov: a scanner from the Prisma Cloud (Palo Alto) family, with a large rule count and strong compliance framework mappings.
Either one alone is enough, and for the hands-on work we go with trivy, which is lighter to install. Let’s run it against the code from the practice series.
$ trivy config envs/dev
HIGH: S3 bucket does not have logging enabled
MEDIUM: Instance metadata service v1 is enabled
...Even code that has been running fine produces findings. Scanner findings get sorted into three buckets: real risks (fix them), risks you knowingly accept (handle as exceptions), and rules that do not fit your situation (disable the rule). What matters most is how you handle the second bucket.
#trivy:ignore:AVD-AWS-0089 -- practice environment, access log bucket not configured. Enable when moving to prod
resource "aws_s3_bucket" "assets" {
# ...
}An exception should be scoped to that one resource, with the reason left as a comment. A codebase piling up reason-less ignores is equivalent to turning the scanner off; with reasons attached, the exceptions themselves become reviewable. checkov supports the same approach with #checkov:skip comments.
Adding it to CI #
Add one step to the PR workflow (#1).
- name: trivy scan
uses: aquasecurity/trivy-action@master
with:
scan-type: config
scan-ref: envs/dev
exit-code: "1"
severity: CRITICAL,HIGHTuning severity is the operational knack here. If you fail the build on MEDIUM findings from day one, the flood of findings from existing code will make the team resent the scanner. Start by blocking only CRITICAL and HIGH, clean up existing findings over time, and raise the bar gradually — that incremental rollout has a much higher adoption rate.
Infracost: putting a price tag on the PR #
The structural cause of cost accidents is when the cost becomes visible: not while the code is being reviewed, but on the end-of-month bill. Decisions like the NAT gateway count in Practice #2 and the instance class in Practice #5 were all cost decisions, and no reviewer can compute those amounts in their head. Infracost is the tool that multiplies the plan output by a price sheet and posts the result as a PR comment.
Example Infracost comment:
aws_db_instance.main
~ instance_class: db.t4g.micro → db.r6g.large
Monthly cost change: +$210 (total $XX → $XX)The moment a one-line instance class change shows up as “+$210/month,” cost review moves from the billing stage to the PR stage. CI integration uses the official action (infracost/actions), and you can start on the free tier (check the current pricing policy at adoption time). The absolute figures are not perfect — usage-based charges like traffic have estimation limits — but for seeing the direction and magnitude of a change, it is more than enough.
Tags: the foundation for tracking after the fact #
If PR guardrails are the advance defense, tags are the foundation for tracking after the fact. Because Practice #1 put Project and Env on every resource via default_tags, Cost Explorer can answer “how much is myapp’s dev costing?” immediately by tag. Turn on a tag-enforcement rule in your scanner and missing tags get caught at the PR stage too. If your account already smells of waste, run through the checklist in AWS Cost Waste Checklist in parallel.
Recap #
What we covered in this post:
- One security scanner is enough: trivy (with tfsec merged in) or checkov. They catch syntactically perfect but risky configurations by comparing against known patterns
- Scope exceptions to individual resources and leave the reason as a comment. An accumulation of reason-less ignores is the same as turning the scanner off
- Start the CI blocking threshold at CRITICAL and HIGH, and raise it gradually
- Infracost comments monthly cost changes on the PR, pulling cost review forward from the bill to the PR
- default_tags-based tagging is the axis of after-the-fact cost tracking, and a tag-enforcement rule prevents omissions
In the next post (#5 Structuring at Scale), we cover structure for when the code and the team grow: the criteria for splitting state into stacks, references between stacks, and the point where Terragrunt becomes necessary.