Safeguard
Cloud Security

Shifting Infrastructure-as-Code security left across the SDLC

Terrascan went archived in November 2025 and tfsec folded into Trivy in 2024 — IaC scanning is consolidating fast, and where you run it matters as much as which tool you pick.

Safeguard Research Team
Research
6 min read

Infrastructure-as-code scanning has quietly consolidated in the last two years, and most teams haven't updated their tooling assumptions to match. Aqua Security folded tfsec into Trivy in 2024 and now directs new development there instead of the standalone project. Tenable, which acquired Terrascan's creator Accurics in 2021, archived Terrascan on November 20, 2025, leaving it unmaintained. Checkov, built by Bridgecrew and now under Palo Alto Networks' Prisma Cloud since Bridgecrew's 2021 acquisition, remains one of the few open-source scanners still under active development, covering Terraform, OpenTofu, CloudFormation, Kubernetes, Helm, Dockerfiles, and ARM/Bicep in one pass. Meanwhile the policy layer has its own split history: HashiCorp Sentinel is the built-in policy-as-code framework for Terraform Cloud and Enterprise, while the Open Policy Agent (OPA), a CNCF project using the Rego language, has become the vendor-neutral standard for the same job via tools like Conftest. None of this matters if a misconfigured aws_s3_bucket resource only gets caught after terraform apply runs against production. This post is a guide to moving that catch point earlier — from a developer's local plan output, through pre-commit hooks, into CI policy gates that block a merge before infrastructure ever changes.

Why does shifting left even matter for infrastructure code?

It matters because IaC misconfigurations are cheaper to fix before a resource exists than after it's provisioned and holding state. A Terraform plan is a proposal — nothing has changed yet — so a security check that runs against terraform plan -out or its JSON export from terraform show -json can block a bad change with zero blast radius. Once apply runs, the same fix means a second change cycle, a state-file diff, and in stateful resources like databases or IAM policies, a window where the misconfiguration was live. terraform validate catches syntax and internal consistency errors before a plan is even generated, making it the cheapest possible check, but it has no opinion on security — an S3 bucket with public-read access validates just fine. The point of shifting left specifically for IaC is stacking checks so that syntax errors die at validate, policy violations die at plan, and only compliant infrastructure reaches apply.

What actually happens when you run terraform plan locally?

terraform plan builds a dependency graph, reconciles it against current state, and produces a list of proposed creates, updates, and deletes without touching real infrastructure. Piping that through -out=tfplan and then terraform show -json tfplan turns it into a structured JSON document that a policy engine can parse programmatically, rather than a human reading colored diff output. This is the mechanical foundation every "shift-left" IaC tool depends on: Checkov, Conftest, and Sentinel all consume this same JSON representation, just with different rule languages on top. Running this locally, in a pre-commit hook or an editor plugin, means a developer sees a flagged security_group with an open 0.0.0.0/0 ingress rule in the same feedback loop as a linter error — seconds after writing it, not minutes later in a CI log they have to scroll back to find.

How do open-source scanners like Checkov differ from policy engines like OPA and Sentinel?

Scanners like Checkov ship pre-built rule catalogs; policy engines like OPA and Sentinel are frameworks you write rules in yourself. Checkov comes with thousands of built-in checks mapped to CIS Benchmarks, NIST 800-53, and PCI-DSS out of the box, so a team gets baseline coverage — public S3 buckets, unencrypted EBS volumes, overly permissive IAM — without writing a single rule. OPA, by contrast, is a general-purpose policy engine using the Rego query language; Conftest wraps it specifically for structured config files like Terraform plan JSON, letting teams write custom rules such as "no resource may be tagged without a cost-center key." Sentinel plays the same role natively inside Terraform Cloud and Enterprise, with three enforcement levels — advisory, soft-mandatory, and hard-mandatory — that determine whether a failing policy can be overridden. In practice, mature programs run both: a pre-built scanner for broad compliance coverage and a policy engine for the organization-specific rules no vendor catalog will ever include.

Where should these checks actually live in a CI pipeline?

They should live as a layered gate — pre-commit for immediate feedback, then a required CI check on every pull request, then a stricter policy gate immediately before apply in the deploy pipeline. Running Checkov or Conftest at pre-commit catches issues before a commit even exists, but it's easy to skip with --no-verify, so it can't be the only layer. A required status check on the pull request, wired into the branch protection rules of GitHub, GitLab, or equivalent, is what actually enforces a policy organization-wide, since merging is blocked until the check passes. The final gate — evaluating the same plan JSON again immediately before apply, inside the deploy job itself — closes the gap where a PR passed review days earlier but the branch has since drifted from what's about to be provisioned. Splitting hard-mandatory blocking rules (public database endpoints, disabled encryption) from advisory ones (missing cost tags) at this stage keeps the gate from becoming something engineers route around.

What does the CI environment itself add to the risk model?

The pipeline running your IaC checks is itself an attack surface, not just a neutral place to run them. The clearest cautionary example is the Codecov Bash Uploader compromise: an attacker modified Codecov's upload script to exfiltrate CI environment variables — starting January 31, 2021 and discovered April 1, 2021 — and because CI environments routinely hold cloud credentials, tokens, and signing keys, the blast radius extended to downstream customers including HashiCorp, Twilio, Rapid7, and Confluent, according to Codecov's own incident disclosure and follow-up reporting from affected vendors. The lesson for IaC pipelines specifically is that a policy gate evaluating your Terraform plan runs in the same environment as the cloud credentials that plan will use to provision real infrastructure. Scoping pipeline credentials to least privilege, pinning third-party actions and scripts to commit hashes rather than mutable tags, and treating the CI runner itself as part of your infrastructure's trust boundary matters as much as the policy rules you write.

How Safeguard helps

Safeguard treats IaC findings as part of one unified findings model alongside SCA, secrets, and container scan results, rather than a separate silo with its own dashboard and its own triage queue. That means a misconfigured Terraform resource, a leaked credential in a .tfvars file, and a vulnerable base image in the container that resource deploys all show up as correlated findings a security team can query together — safeguard findings list --engine iac --severity high alongside the same command for sast, sca, or secrets. Those findings feed the same CI policy-gate flow used for every other engine, so IaC checks become one more required status check blocking a merge rather than a scanner engineers have to remember to run manually before apply.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.