IaC security scanning: fix the template, or the finding comes back
An engineer gets a ticket: a storage bucket allows public access. They open the cloud console, turn public access off, and close the ticket. A week later the same finding is back. Nobody re-opened the bucket by hand. The next terraform apply recreated it exactly as the template describes it, because the template was never changed.
This loop is one of the most common reasons cloud security programmes feel busy without improving. The fix is not working harder on the console. It is scanning and fixing infrastructure as code (IaC), and connecting runtime findings back to the code that created them.
Why console fixes do not stick
When infrastructure is managed as code, the code is the source of truth. Terraform, CloudFormation, Helm charts and Kubernetes manifests describe the desired state, and every apply pushes the cloud back towards that state. A manual change in the console is drift. Depending on how the resource is managed, the next deployment either reverts it silently or shows it as an unexpected diff that someone "fixes" by re-applying.
The result is a finding that keeps coming back, gets triaged again, and wears down trust in the security tool that keeps reporting it.
What IaC security scanning does
IaC security scanning evaluates infrastructure templates against security policy before anything is created. Typical checks include:
- Storage with public access or without encryption.
- Network rules open to
0.0.0.0/0on sensitive ports. - Databases without encryption, backups or deletion protection.
- Identity policies with wildcard actions or resources.
- Kubernetes workloads running privileged, as root, or with host mounts.
- Logging turned off on services that should be audited.
Scanning can run in three places, and mature teams use all three:
- In the editor or pre-commit, so the engineer sees the issue while writing the code.
- In the pull request, so the reviewer sees it and the pipeline can gate on it.
- Against the plan, so what is checked is what will actually change, including values from variables and modules.
How teams handle it today
The usual starting point is a standalone IaC scanner added to CI. It helps, but three gaps show up quickly:
- Different rules in code and in the cloud. The IaC scanner and the runtime posture tool each have their own policy set. A template passes in CI and the resource it creates fails in production, or the reverse, and engineers stop trusting either.
- No link back from runtime. When a runtime finding appears, nobody can say which repository, file and resource block created it, so the fix lands in the console again.
- Everything fails the build. The first scan of an existing repository finds hundreds of issues. If the pipeline blocks on all of them, the gate is disabled within weeks.
A checklist for IaC security that holds
Coverage
- All IaC formats in use are scanned: Terraform, CloudFormation, Helm, raw Kubernetes manifests, and any others your teams use.
- Modules and shared templates are scanned at their source, since one bad module spreads to every consumer.
- Scans run on every pull request, not only on the main branch.
Policy
- One policy set for code and for runtime, so a pass in CI means the same thing as a pass in production.
- Every rule has a clear explanation and an example of the compliant configuration.
- Exceptions are recorded with a reason and an expiry, not by deleting the rule.
Gating
- Gate on newly introduced findings. Work the existing backlog separately, on a schedule.
- Start with a small set of high-severity rules as blocking. Add more as the backlog shrinks.
- Make the gate's output readable in the pull request, with the file and line.
Provenance
- Every runtime finding on an IaC-managed resource records which repository, template and resource block created it.
- Tickets for those findings go to the code owner, not to whoever has console access.
- The ticket asks for a code change. A console-only fix on a managed resource is treated as incomplete.
Verification
- After the code fix merges and deploys, the runtime finding is re-evaluated and closes on evidence.
- If the finding reappears, it is flagged as a regression, and the provenance shows which change brought it back.
Handling the backlog
The first full scan of a mature codebase is usually discouraging. Some practical ways through it:
- Group findings by module or template. One shared module is often responsible for a large share of them.
- Fix the modules first. Every consumer improves on its next apply.
- Leave findings in abandoned or archived code until last, or retire that code.
- Track the trend of new findings per week. That number should fall first, and it is the one that shows the gate is working.
How Onam approaches it
Onam's Code Security engine checks Terraform, Kubernetes manifests, CloudFormation templates and Dockerfiles in a repository as part of every scan, alongside static analysis, dependency analysis and secret detection. The IaC checks use their own rule set, separate from the rules the runtime posture engine applies to deployed resources, and Onam does not yet trace a runtime finding back to the template line that created it — so the discipline described above, fixing in code rather than the console, is still yours to enforce.
On gating, Onam has no CI plugin today: a scan reports, and a pipeline that wants a gate calls the scan API and decides for itself (CI usage). For static-analysis findings in application code, AI Code Fix can rewrite the affected files on a separate branch for your team to review; nothing merges itself.
Request a demo to see a repository scanned end to end.