Infrastructure-as-Code Security Scanning: Catching Misconfigurations Before Deployment
AI generated
OWASP
0x00
Security · Infrastructure as Code · Terraform · Shift Left
Infrastructure-as-Code Security Scanning
catching misconfigurations before they go live

An open security group that accidentally allows access from the entire internet, or a storage bucket without encryption, rarely comes from malicious intent. It usually comes from an overlooked default value in a Terraform file. Infrastructure-as-Code security scanning checks exactly these configurations automatically, before they are ever applied, preventing misconfigurations from surfacing only through a manual audit or, worse, through an actual incident.

15 min read tfsec · Checkov · Policy as Code Terraform · Docker Compose · Shift Left

1. The shift-left principle for infrastructure security

Shift-left means running a check as early as possible in the development process, instead of leaving it until the end, right before or even after deployment. For Infrastructure as Code, that concretely means checking a Terraform configuration for security issues automatically during development and, at the latest, in the pull request, rather than waiting for a quarterly manual infrastructure audit.

The difference matters a lot in practice: a misconfiguration caught in a pull request costs the author a few minutes to fix. The same misconfiguration only discovered months later during a manual audit may already be running in production, may have already processed real traffic, and requires a coordinated, risky change to live infrastructure.

2. Common misconfigurations scanners reliably catch

Among the most frequent findings are security groups or firewall rules that open a port to access from 0.0.0.0/0, even though only an internal network should ever reach it. Just as common are storage resources like S3 buckets or database instances where encryption at rest is not enabled, even though the cloud provider offers that option at no extra cost.

Other classic findings include IAM roles with excessively broad permissions, such as a wildcard in a policy's resource statement, and missing logging configuration, which would make forensic analysis harder in an actual incident. Each of these misconfigurations can be detected automatically based on a clearly stated rule, without a human having to read through the configuration by hand.

3. tfsec versus Checkov

tfsec, now part of Trivy, specializes in Terraform and analyzes configuration statically, without needing to run a terraform plan. It ships with an extensive, ready-to-use rule set for all major cloud providers and integrates into a pipeline with very little configuration effort.

Checkov by Bridgecrew covers, beyond Terraform, additional formats such as CloudFormation, Kubernetes manifests, Docker Compose, and Dockerfiles, making it the better tool when a team maintains multiple infrastructure formats in parallel. Checkov also allows defining custom rules in Python, while tfsec offers custom rules through a simpler, declarative structure.


# GitLab CI: Checkov as a mandatory stage before terraform apply
stages:
  - security-scan
  - plan
  - apply

checkov-scan:
  stage: security-scan
  image: bridgecrew/checkov:latest
  script:
    - checkov -d ./infrastructure
        --framework terraform
        --compact
        --soft-fail-on LOW,MEDIUM
        --hard-fail-on HIGH,CRITICAL
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'

terraform-plan:
  stage: plan
  needs: ["checkov-scan"]
  script:
    - terraform init
    - terraform plan -out=tfplan

4. Policy-as-code with Open Policy Agent

While tfsec and Checkov work with pre-built rules, policy-as-code with Open Policy Agent and its rule language Rego lets you express organization-specific policies as code that go beyond the standard rule sets. One example would be an internal requirement that every resource in the production environment carries a specific tagging scheme, something no generic security scanner checks on its own.

The advantage of policy-as-code is that these organization-specific rules can be versioned, tested, and evaluated in the same pull request workflow as generic security rules. That creates a unified review process covering both industry-wide best practices and individual compliance requirements, without having to maintain two separate tools in parallel.

5. Terraform-specific checks in detail

For Terraform, scanners increasingly check not just isolated resource blocks but also the context between resources, for instance whether a publicly reachable load balancer rule actually hits a private subnet configuration. This context-aware checking cuts down on false positives significantly, since a rule that looks open at first glance can be harmless overall if another resource already restricts it.

Modern scanners additionally check the planned state of a terraform plan, not just the static code, which reveals misconfigurations that only emerge from the combination of variables and modules working together and would not be visible in the isolated source code alone.

6. Checking Docker Compose configurations for misconfigurations

Docker Compose files frequently carry security problems too, such as containers running in privileged mode even though the application does not need it, or volumes that mount sensitive host paths like the Docker socket into the container unprotected. Checkov covers exactly these patterns and can run in the same pipeline that also checks the Terraform configuration.

Such configurations creep in especially easily in development environments, since a privileged container makes debugging easier in the short term. But if that compose file gets carried over unchanged as a template for a production environment, it turns into a real security risk, one an automated scan reliably catches before it gets that far.

7. Integrating into the pull request workflow

For Infrastructure-as-Code scanning to actually work, the result has to show up where developers already work: directly as a comment on the pull request, with a specific line reference and an understandable explanation of why a given configuration is flagged as problematic. A plain log entry in a CI dashboard nobody actively checks has little practical effect.

Many teams additionally configure the scan as a mandatory status check that blocks a merge while critical findings remain open, while lower-severity findings show up as a warning in the comment without preventing the merge. That tiered approach keeps the team from perceiving the gate as a pure obstacle and looking for ways to systematically bypass it.

8. Handling exceptions and deliberate risk acceptance

Not every reported misconfiguration is actually a risk in its concrete context. An open port might be justified, for example, if it exists solely for a public, intentionally unauthenticated health check endpoint. For such cases, tfsec and Checkov support inline comments directly in the Terraform code that exclude a specific rule for a specific resource in a targeted, traceable way.

What matters is that every exception carries a short justification in the same comment and stays visible in code review. An exception without a stated reason looks identical, in hindsight, to a simply overlooked misconfiguration, which makes it practically impossible to later tell deliberate risk acceptance apart from a genuine oversight.

9. From a one-time scan to continuous compliance monitoring

A scan on the pull request only covers changes that actually get introduced through code. In practice, drift also happens through manual changes made directly in the cloud console, for instance when someone quickly adjusts a rule in an emergency and forgets to backport that change into Terraform afterward.

Continuous compliance monitoring, which regularly checks the actual state of the cloud environment against the same rules that apply in the pull request scan, catches exactly this drift between code and reality. That keeps security standards enforced not just at deployment time but permanently, regardless of which path a change actually took.

Tool Coverage Format Policy engine
tfsec Terraform HCL built-in rule set, part of Trivy
Checkov Terraform, CloudFormation, Kubernetes, Docker Compose HCL, YAML, JSON built-in, extensible in Python
Open Policy Agent (Rego) arbitrary, via Conftest JSON plan output freely defined Rego policies
Terrascan Terraform, Kubernetes, Helm HCL, YAML based on Open Policy Agent

Mironsoft

Security audits, OWASP-compliant hardening, and secure architecture

Applications that actually hold up against a real attack attempt?

We review existing applications for classic OWASP vulnerabilities, insecure authentication, and missing input validation, then build an architecture that structurally reduces attack surface instead of just patching individual symptoms.

Security Audit

Systematically checking OWASP Top 10, auth flows, and input validation for vulnerabilities.

Secure Architecture

Building rate limiting, encryption, and access controls correctly from the ground up.

Incident Readiness

Establishing logging, monitoring, and response processes for when things go wrong.

10. Summary

IaC Security Scanning: The Essentials at a Glance

Core idea

Catch misconfigurations in code before they ever get applied.

Tools

tfsec for pure Terraform, Checkov for multiple formats including Docker Compose.

Extension

Policy-as-code with Open Policy Agent covers organization-specific rules.

Complement

Continuous compliance monitoring catches drift caused by manual changes.

11. FAQ: IaC Security Scanning: The Essentials at a Glance

1What does shift-left mean for infrastructure security?
Shift-left means running security checks as early as possible in the development process, ideally already in the pull request, instead of only during a later manual audit or after an incident.
2What is the difference between tfsec and Checkov?
tfsec specializes in Terraform and works purely statically, while Checkov additionally covers formats like CloudFormation, Kubernetes, and Docker Compose, and allows custom rules written in Python.
3What misconfigurations do these scanners typically find?
Common findings include open security groups that allow access from the entire internet, missing encryption on storage resources, excessively broad IAM permissions, and missing logging configuration.
4What is policy-as-code with Open Policy Agent?
Policy-as-code lets you express organization-specific policies as code in the Rego language and check them automatically, in addition to the generic rules from tools like tfsec or Checkov.
5How are exceptions for deliberately accepted risks documented?
Through inline comments directly in the Terraform code that exclude a specific rule for a specific resource while carrying a short justification visible in code review.
6Why isn't a scan on the pull request alone enough?
Because drift can also happen through manual changes made directly in the cloud console that never go through code. Continuous compliance monitoring catches that drift between code and actual state.
7Can you scan Docker Compose files too?
Yes, Checkov covers Docker Compose files and finds issues there such as privileged containers or unprotected mounts of sensitive host paths like the Docker socket.
8How do you keep a scan gate from being seen as a pure obstacle?
Through a tiered approach where only critical and high findings block a merge, while lower-severity findings show up as a visible but non-blocking warning on the pull request.
9Do these tools only check individual resources in isolation?
Modern scanners increasingly check the context between resources too, and in some cases the planned state of a terraform plan, to catch misconfigurations that only emerge from multiple resources working together.
10Does automated scanning fully replace a manual security audit?
No, automated scanning reliably and quickly covers known patterns, but a periodic manual audit remains valuable for assessing architectural risks that no rule-based tool can detect on its own.