Terraform’s declarative nature makes it powerful for infrastructure as code, but it also means a single typo or outdated module can ripple into significant misconfigurations. Trivy, a popular open-source vulnerability scanner, can inspect your Terraform code before it ever hits terraform apply, catching these issues early.

Let’s see Trivy in action. Imagine you have a simple main.tf file defining an AWS S3 bucket:

resource "aws_s3_bucket" "my_bucket" {
  bucket = "my-unique-bucket-name-12345"

  tags = {
    Environment = "Dev"
  }
}

You can scan this file with Trivy using the following command:

trivy config main.tf

Trivy will then output its findings. For instance, it might flag the S3 bucket for not having versioning enabled, a common security best practice.

main.tf:
[INFO] Detecting vulnerabilities...
[INFO] AWS S3 Bucket Encryption check
[INFO] AWS S3 Bucket Versioning check
[WARN] S3 bucket "my-unique-bucket-name-12345" does not have versioning enabled.

This output is direct and actionable. It tells you exactly which resource (my-unique-bucket-name-12345) and which policy (versioning) is the concern.

The Mental Model: Shifting Left with Trivy

The core problem Trivy addresses in IaC is the "shift-left" paradigm. Traditionally, security and compliance checks happened late in the development lifecycle, often after infrastructure was provisioned, making remediation costly and time-consuming. Trivy allows you to integrate these checks directly into your development workflow, scanning .tf files, CloudFormation templates, Kubernetes manifests, and more, right alongside your code.

Internally, Trivy parses your IaC files, creating an abstract syntax tree (AST) representation. It then applies a set of built-in, continuously updated policies (rules) to this AST. These policies are designed to detect common security misconfigurations, compliance violations, and even insecure patterns. Trivy’s strength lies in its broad coverage of cloud providers (AWS, Azure, GCP) and its ability to understand the nuances of different IaC syntaxes.

The levers you control are primarily the config command and its various flags. You can target specific files or directories, ignore certain findings, and even define your own custom policies using Rego (the policy language used by Open Policy Agent).

Understanding Trivy’s Policy Engine

Trivy’s policy engine evaluates your IaC against a predefined set of security benchmarks and best practices. For example, when it checks for S3 bucket versioning, it’s not just looking for a specific string. It’s parsing the aws_s3_bucket resource block, identifying the bucket attribute, and then checking for the presence and correct configuration of the versioning_configuration block. If that block is missing or configured to false, it triggers a warning. This deep understanding of resource attributes and their expected configurations is what makes Trivy effective.

When Trivy scans your Terraform code, it’s not executing terraform plan or terraform apply. Instead, it’s performing a static analysis of the code itself. It understands the relationships between resources defined in your .tf files, how variables are used, and how modules are composed. This allows it to detect potential issues even before you run a terraform plan, providing an even earlier feedback loop. For instance, if you define an AWS security group that allows all inbound traffic on port 22 (SSH) from anywhere (0.0.0.0/0), Trivy will flag this as a high-severity issue because it’s a common attack vector.

trivy config main.tf

If main.tf contained:

resource "aws_security_group" "ssh_access" {
  name        = "allow_ssh_from_anywhere"
  description = "Allow SSH inbound traffic"

  ingress {
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    Environment = "Dev"
  }
}

Trivy would likely output something like:

main.tf:
[INFO] Detecting vulnerabilities...
[INFO] AWS Security Group Ingress Rule check
[WARN] Security group "allow_ssh_from_anywhere" allows SSH access from 0.0.0.0/0.

This is invaluable for maintaining a secure posture across your infrastructure. Trivy doesn’t just look at individual resource configurations; it can also understand dependencies and the overall architecture being defined. For example, if you’re defining a Kubernetes deployment that mounts a sensitive secret as an environment variable instead of using a dedicated secret volume, Trivy will identify this as a security risk.

The real power comes from integrating Trivy into your CI/CD pipeline. You can configure your pipeline to fail if Trivy detects any critical or high-severity misconfigurations, preventing insecure code from ever reaching production. This proactive approach drastically reduces the likelihood of costly security breaches and compliance failures.

Many users are unaware that Trivy’s config command can also scan other IaC formats like CloudFormation, Kubernetes YAML, Dockerfiles, and even docker-compose.yml files. This unified scanning approach simplifies security tooling across different infrastructure and application deployment methods, allowing you to maintain a consistent security baseline regardless of the specific technology stack.

The next step after ensuring your IaC is secure is to integrate Trivy with your Git repository for automated scanning on every commit.

Want structured learning?

Take the full Trivy course →