# Terraform Security Scanning with tflint, Checkov and Trivy

> Find misconfigurations in Terraform and OpenTofu code before deploying: tflint for errors, Checkov and Trivy for AWS security issues, with CI examples.

- Source: https://www.itwonderlab.com/terraform-security-scanning-tflint-checkov-trivy/
- Published: 2026-06-02
- Updated: 2026-06-02
- Author: Javier Ruiz Jiménez (https://www.javierruizjimenez.com/)
- Site: IT Wonder Lab (https://www.itwonderlab.com/)

---

## Static analysis for infrastructure code

Reviewing a plan by eye does not catch everything: an S3 bucket without encryption, a [security group](https://www.itwonderlab.com/aws-security-groups/) open to `0.0.0.0/0` on port 22 or an unencrypted RDS volume are valid configurations that `validate` accepts. Static analysis tools read the code (or the plan) and report them before deployment. They are part of the [testing](https://www.itwonderlab.com/terraform-testing-opentofu-test/) pipeline.

### tflint: errors and conventions

[tflint](https://github.com/terraform-linters/tflint) is a linter. With the AWS ruleset it detects invalid values that only fail at apply time (a wrong instance type, a deprecated argument) and enforces conventions such as documented variables.

```hcl title=".tflint.hcl"
plugin "terraform" {
  enabled = true
  preset  = "recommended"
}

plugin "aws" {
  enabled = true
  version = "0.38.0"
  source  = "github.com/terraform-linters/tflint-ruleset-aws"
}
```

```shell
$ tflint --init
$ tflint --recursive
```

Check the plugin repository for the current version number.

### Checkov: policies for many clouds

[Checkov](https://www.checkov.io/) has hundreds of built-in policies for AWS, Azure, GCP and Kubernetes, mapped to benchmarks such as CIS.

```shell
$ pip install checkov
$ checkov -d . --framework terraform
```

Typical output:

```shell
Check: CKV_AWS_18: "Ensure the S3 bucket has access logging enabled"
	FAILED for resource: aws_s3_bucket.logs
	File: /main.tf:1-4
```

### Trivy: misconfigurations, secrets and more

[Trivy](https://trivy.dev/) (which includes the former tfsec checks) scans configuration, container images, dependencies and leaked secrets with one tool:

```shell
$ trivy config .
$ trivy config --severity HIGH,CRITICAL --exit-code 1 .
```

`--exit-code 1` makes the command fail when it finds issues of that severity, which is what a CI job needs.

### Scanning the plan

Scanning the plan catches problems with values that are only known after evaluation (variables, modules):

```shell
$ tofu plan -out=tfplan
$ tofu show -json tfplan > tfplan.json
$ checkov -f tfplan.json
```

### Handling false positives

Not every finding applies. Suppress it where it happens and explain why, so the decision is visible in code review:

```hcl title="main.tf"
resource "aws_s3_bucket" "public_site" {
  bucket = "ditwl-public-site"

  #checkov:skip=CKV_AWS_18:Access logs are not needed for a public static site
}
```

Trivy uses `#trivy:ignore:AVD-AWS-0089`. Avoid global ignores: they hide future real problems.

### In CI

```yaml title=".github/workflows/security.yml"
name: security
on: pull_request

jobs:
  scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: aquasecurity/trivy-action@master
        with:
          scan-type: config
          severity: HIGH,CRITICAL
          exit-code: "1"
```

Pin actions to a version or commit in production. See the complete [GitHub Actions pipeline](https://www.itwonderlab.com/terraform-github-actions-aws-oidc/).

### Which one to choose

Start with Trivy or Checkov, plus tflint. They overlap a lot, so running all the scanners adds noise. Add a policy engine such as OPA or Sentinel only when you need custom organization rules. Do not forget [secrets management](https://www.itwonderlab.com/terraform-secrets-management/): scanners also find hard-coded credentials.
