Terraform is the dominant infrastructure-as-code tool, and that makes it a critical security surface. A misconfigured Terraform resource can expose databases to the internet, create overly permissive IAM roles, or disable encryption on storage buckets. These are not edge cases -- they are the most common cloud security incidents.
Security scanning for Terraform catches these misconfigurations before they become incidents. But the way you implement scanning matters. Do it wrong and you get a flood of false positives that developers ignore. Do it right and you catch real issues before they reach production.
Why Terraform Needs Security Scanning
Infrastructure-as-code is fundamentally code, and code needs review. But Terraform has characteristics that make manual review insufficient.
Scale. A moderately complex AWS environment might have thousands of Terraform resources across hundreds of files. No human can manually verify the security properties of every resource definition.
Implicit dependencies. A security group rule might look fine in isolation, but when combined with a load balancer configuration and an EC2 instance definition, it creates a publicly accessible path to a private subnet. These cross-resource security implications are hard to spot in code review.
Drift from intent. Terraform modules abstract away complexity, which is their purpose. But abstraction means that a developer calling a module might not realize that the module creates a public S3 bucket or an unencrypted RDS instance. Scanning the plan output catches what the module produces, not just what the developer intended.
Choosing Your Scanning Tools
The Terraform security scanning ecosystem has matured significantly. Here are the tools that work well in practice.
Checkov is the most comprehensive open-source option. It supports Terraform HCL, Terraform plan files, and many other IaC formats. It has hundreds of built-in policies covering AWS, Azure, and GCP, and supports custom policies written in Python or YAML.
tfsec (now part of Trivy) provides fast HCL scanning with good coverage and clear output. It is less comprehensive than Checkov but faster and easier to integrate into quick feedback loops.
Terrascan supports multiple IaC formats and uses Open Policy Agent (OPA) for policy evaluation. If your organization already uses OPA for Kubernetes admission control, Terrascan lets you reuse that investment.
Sentinel is HashiCorp's commercial policy-as-code framework for Terraform Cloud and Enterprise. If you are on Terraform Cloud, Sentinel provides native policy enforcement that runs as part of the plan-apply workflow.
Snyk IaC and Prisma Cloud offer commercial scanning with broader platform integration. They add value if you need a single tool that covers IaC, container images, and application dependencies.
My recommendation: start with Checkov or tfsec for immediate value. Add Sentinel if you use Terraform Cloud. Consider commercial tools when you need platform-level integration.
Where to Scan in the Workflow
Scanning at a single point is not enough. Different scanning points catch different issues.
IDE Integration
Give developers immediate feedback by running tfsec or Checkov in their editor. VS Code extensions exist for both tools. This catches the simplest issues -- unencrypted resources, overly permissive security groups, missing tags -- before the code is even committed.
The limitation of IDE scanning is that it only sees the files currently open. It cannot evaluate cross-file dependencies or the full plan output.
Pre-Commit Hooks
Pre-commit hooks run scanning before code is committed to the repository. This is more comprehensive than IDE scanning because it can evaluate all changed files together.
Use pre-commit framework with Checkov or tfsec hooks. Keep the scan focused on changed files to keep commit times reasonable.
Pull Request Scanning
This is the most important scanning point. Run comprehensive scanning in your CI pipeline on every pull request. Post results as PR comments so reviewers can see security findings alongside the code changes.
PR scanning should evaluate the full Terraform plan, not just the HCL files. A plan-based scan catches issues that HCL scanning misses, such as values computed from data sources or module outputs that create security-relevant configurations.
Pre-Apply Scanning
The final gate before infrastructure changes are applied. This runs against the actual Terraform plan in the deployment pipeline. If scanning fails, the apply does not proceed.
Pre-apply scanning is your last line of defense. It should be strict but not fragile. Use a well-tested policy set and have a documented exception process for legitimate findings that need to be temporarily suppressed.
Writing Effective Custom Policies
Built-in policies cover common misconfigurations, but every organization has unique security requirements.
Start with your incidents. Look at your past cloud security incidents. If you had a publicly accessible RDS instance last year, write a policy that prevents it. Real incidents make the best policies because they capture actual risks, not theoretical ones.
Be specific, not comprehensive. A policy that says "all S3 buckets must be encrypted" is useful. A policy that says "all resources must be secure" is not. Specific policies produce specific findings that developers can act on.
Include remediation guidance. Every custom policy should include a description of why it exists and how to fix a violation. "S3 bucket missing server-side encryption" is a finding. "S3 bucket missing server-side encryption -- add server_side_encryption_configuration block with AES256 or aws:kms" is actionable.
Test your policies. Write test cases for every custom policy. Include both passing and failing examples. Test that the policy catches what it should and does not flag what it should not.
Managing False Positives
False positives are the biggest threat to a successful Terraform scanning program. Too many false positives and developers start ignoring all findings.
Suppress with intention. Use inline suppression comments (#checkov:skip=CKV_AWS_18:Reason) for legitimate exceptions. Require a reason for every suppression so it can be reviewed later.
Review suppressions in PRs. Treat suppression comments like security-relevant code changes. Reviewers should validate that the suppression is justified and the reason is legitimate.
Track suppression rates. If more than 20% of your findings are being suppressed, your policy set is too aggressive for your environment. Tune it.
Separate policies by environment. Development and production have different security requirements. A public S3 bucket in a development sandbox might be acceptable. The same configuration in production is not. Use different policy sets for different environments.
Terraform State Security
Terraform state files contain sensitive information and are often overlooked in security scanning.
Encrypt state at rest. If you use S3 backends, enable server-side encryption and versioning. If you use Terraform Cloud, state is encrypted by default.
Restrict state access. Your state file contains resource IDs, IP addresses, and potentially credentials. Limit who can read state to the CI/CD pipeline and authorized operators.
Never commit state to version control. This seems obvious, but .gitignore configurations get missed. Add scanning for accidentally committed state files to your CI pipeline.
Use state locking. Enable DynamoDB locking for S3 backends to prevent concurrent state modifications that could corrupt state or create race conditions.
Module Security
Terraform modules are reusable packages of infrastructure. They are also a supply chain risk.
Audit third-party modules. Modules from the Terraform Registry are community-maintained. Review the source code before using them. Check the module's maintenance status, open issues, and security track record.
Pin module versions. Always specify an exact version for module sources. Never use an unpinned module reference that could resolve to a newer, potentially compromised version.
Maintain internal modules. For common infrastructure patterns, maintain your own modules with security best practices baked in. An internal "secure S3 bucket" module that enables encryption, blocks public access, and sets proper policies by default is more valuable than a policy that flags every S3 bucket without those settings.
How Safeguard.sh Helps
Safeguard.sh extends your Terraform security scanning with supply chain context. It tracks the dependencies in your Terraform configurations -- provider versions, module sources, and the container images referenced in your infrastructure definitions. When a vulnerability is disclosed in a Terraform provider or a referenced container image, Safeguard.sh alerts you and identifies every configuration affected.
The platform integrates with your CI/CD pipeline to provide security scanning alongside SBOM generation and dependency analysis, giving you a complete picture of your infrastructure's security posture from code to deployment.