Checkov, Trivy and tflint
Checkov, Trivy and tflint are the three static scanners that run on every infrastructure change before a plan, and Trivy also scans every container image before it is pushed. They catch misconfigurations, known vulnerabilities and provider mistakes at review time, when they are cheapest to fix.
What it does
- Checkov evaluates infrastructure code against a library of policies (encryption on, logging on, no open security groups) and reports each failing check by id, such as
CKV_AWS_338. - Trivy scans two things: infrastructure code for misconfigurations (ids such as
AVD-AWS-0104), and container images for operating-system and library vulnerabilities. - tflint lints OpenTofu code for the AWS provider: invalid instance types, deprecated arguments and unused declarations that a plan would only catch later, or never.
How BuiltForProd uses it
Before commit. Every infrastructure repository's .pre-commit-config.yaml runs Checkov (version 3.3.19, Terraform framework) and Trivy through the terraform_trivy hook, skipping the generated and cached folders. The AWS Baseline adds terraform_tflint with the shared .tflint.hcl. The code repositories run Checkov over the whole tree.
In CI. The Baseline's plan.yml has a lint-and-scan job that must pass before any plan: tofu fmt, tflint (v0.64.0 with the AWS ruleset 0.48.0), Checkov over modules/ with soft_fail: false, and a Trivy configuration scan of modules/. The blueprint plan workflows run the format check and the layout guards; their Checkov and Trivy runs are the pre-commit hooks. The code repositories' ci.yml builds the image and runs Trivy against it, failing on CRITICAL and HIGH vulnerabilities that have a fix.
tflint scope. .tflint.hcl lints only the platform's own modules (call_module_type = "none", since registry modules are linted upstream) and disables the terraform_required_version and terraform_required_providers rules, because those blocks are generated into every unit by root.hcl rather than written in modules.
Suppressions carry a reason. Where a check does not apply, the code says why inline: #checkov:skip=CKV_AWS_338: CloudWatch log group retention is set to 365 days on the EKS module, trivy:ignore:AVD-AWS-0104 on the egress rule that hub-and-spoke routing requires, and a .trivyignore for a rule that lives inside an upstream module and cannot be annotated. Two Checkov ids for node-group launch templates are skipped at the command line for the same reason. A reviewer can read every exception in place; the policy as code page covers the principle.
Terms you will see
| Term | Meaning |
|---|---|
| Check id | The identifier of one policy, such as CKV_AWS_18 or AVD-AWS-0136. |
| Skip or ignore | An inline annotation that suppresses one check with a justification. |
| Soft fail | Reporting without failing the job; off in the Baseline's CI. |
| Ruleset | tflint's plugin of provider-specific rules. |
| Fixable vulnerability | A CVE with a patched version available; the image gate fails only on these. |
Where to read more
- Policy as code
- pre-commit for where the hooks are wired
- GitHub Actions for the CI jobs
- Docker for the images Trivy scans