# Terraform
Trivy supports the scanners listed in the table below.

|     Scanner      | Supported |
|:----------------:|:---------:|
| Misconfiguration |     ✓     |
|      Secret      |     ✓     |

It supports the following formats:

|     Format    | Supported |
|:-------------:|:---------:|
|     JSON      |     ✓     |
|      HCL      |     ✓     |
| Plan Snapshot |     ✓     |
|   Plan JSON   |     ✓     |

Trivy can scan Terraform Plan files (snapshots) or their JSON representations. To create a Terraform Plan and scan it, run the following command:
```bash
terraform plan --out tfplan
trivy config tfplan
```

To scan a Terraform Plan representation in JSON format, run the following command:
```bash
terraform show -json tfplan > tfplan.json
trivy config tfplan.json
```

## Misconfiguration
Trivy recursively searches directories and scans all found Terraform files.
It also evaluates variables, imports, and other elements within Terraform files to detect misconfigurations.

### Value Overrides
You can provide `tf-vars` files to Trivy to override default values specified in the Terraform HCL code.

```bash
trivy config --tf-vars dev.terraform.tfvars ./infrastructure/tf
```

### Exclude Downloaded Terraform Modules
By default, downloaded modules are also scanned.
If you don't want to scan them, you can use the `--tf-exclude-downloaded-modules` flag.

```bash
trivy config --tf-exclude-downloaded-modules ./configs
```

## Secret
The secret scan is performed on plain text files, with no special treatment for Terraform.

## Limitations

### Terraform configurations

#### Filesystem functions

Trivy treats the scan root as a trust boundary: only files within it are considered trusted input.
Functions such as `file()`, `filebase64()`, and related file-reading functions cannot access paths outside the scanned directory.

```hcl
# Works: path is within the scan root
user_data = file("scripts/bootstrap.sh")

# Fails: path escapes the scan root
user_data = file("../shared/bootstrap.sh")
```

This can affect configurations that reference shared files from a parent directory, for example, when scanning a subdirectory such as `envs/production/`, while shared files live at the repository root.

**Workaround:** scan from the repository root so all referenced files fall within the scan boundary:

```bash
trivy config --skip-dirs envs/staging ./
```

If certain checks produce false positives due to unresolved `file()` calls, they can be suppressed using `--ignore-policy` or inline `# trivy:ignore` comments.

#### Data sources and computed attributes

Trivy relies on static analysis of Terraform configurations. As a result, data sources and
resource attributes whose values are only known after creation or update are not fully supported.

Terraform evaluates `data` blocks by querying the provider during the `plan` phase. However,
Trivy does not execute provider calls and therefore cannot resolve values that depend on
external or cloud state. Such values are treated as `unknown` during static analysis.

The same limitation applies to resource attributes marked as computed, whose values become
available only after a resource is created or updated (for example, autogenerated IDs, IP addresses,
or DNS names).

Because of this, expressions that depend on `data` blocks or computed attributes may:

- be evaluated as `unknown`, or
- fall back to default values (for example, when using the `try` function),

which can lead to false positives or false negatives during misconfiguration detection.

### Terraform Plan JSON

#### for_each and count in expressions

The plan created by Terraform does not provide complete information about references in expressions 
that use `each` or `count` objects. For this reason, in some situations it is not possible 
to establish references between resources that are needed for checks when detecting misconfigurations.
An example of such a configuration is:

```hcl
locals {
  buckets = toset(["test"])
}

resource "aws_s3_bucket" "this" {
  for_each = local.buckets
  bucket   = each.key
}

resource "aws_s3_bucket_acl" "this" {
  for_each = local.buckets
  bucket   = aws_s3_bucket.this[each.key].id
  acl      = "private"
}
```

With this configuration, the plan will not contain information about which attribute 
of the `aws_s3_bucket` resource is referenced by the `aws_s3_bucket_acl` resource.

See more [here](https://github.com/hashicorp/terraform/issues/30826).