# Scan Virtual Machine Images with Trivy: AWS AMI, EBS Snapshots, and VMDK Files

> Easily scan AWS AMI, EBS snapshots, and VMDK files for vulnerabilities using Trivy. Secure your virtual machine images with simple commands.

- Repository: [Aqua Security/trivy](https://github.com/aquasecurity/trivy)
- Tags: how-to-guide
- Published: 2026-03-23

---

**Run `trivy vm ami:<ami-id>` or `trivy vm ebs:<snapshot-id>` to scan remote AWS virtual machine images, or `trivy vm <path>` for local VMDK disk files.**

The `aquasecurity/trivy` repository treats virtual machine images as a first-class **artifact type** called `vm`, enabling comprehensive vulnerability, secret, and license detection on AWS AMIs, EBS snapshots, and local disk images without requiring running instances.

## How Trivy Scans Virtual Machine Images

When you invoke the `vm` subcommand, Trivy initializes a specialized scanning pipeline distinct from container or filesystem scans. In [`pkg/commands/app.go`](https://github.com/aquasecurity/trivy/blob/main/pkg/commands/app.go) (lines 1076-1118), the CLI registers the `vm` command and defines the **AWS flag group** (`flag.AWSFlagGroup`) for authentication and region configuration. The command instantiates a `vmStandaloneScanService` (defined in [`pkg/commands/artifact/scanner.go`](https://github.com/aquasecurity/trivy/blob/main/pkg/commands/artifact/scanner.go), lines 13-25) that orchestrates the scan workflow.

### Target Type Detection

The entry point for VM scanning is `vm.NewArtifact` in [`pkg/fanal/artifact/vm/vm.go`](https://github.com/aquasecurity/trivy/blob/main/pkg/fanal/artifact/vm/vm.go) (lines 39-73). This function calls `detectType` to classify the target based on string prefixes:

- **`ami:`** – Triggers `newAMI` for Amazon Machine Image IDs (line 60), implemented in [`pkg/fanal/artifact/vm/ami.go`](https://github.com/aquasecurity/trivy/blob/main/pkg/fanal/artifact/vm/ami.go)
- **`ebs:`** – Triggers `newEBS` for EBS snapshot IDs (lines 63-68), implemented in [`pkg/fanal/artifact/vm/ebs.go`](https://github.com/aquasecurity/trivy/blob/main/pkg/fanal/artifact/vm/ebs.go)
- **(no prefix)** – Treats the path as a local file and invokes `newFile` (lines 70-71)

### The VM Walker and Disk Parsing

Once the artifact type is determined, Trivy uses `walker.NewVM()` (implemented in [`pkg/fanal/walker/vm.go`](https://github.com/aquasecurity/trivy/blob/main/pkg/fanal/walker/vm.go)) to traverse the virtual disk. For VMDK-formatted images, the walker leverages the VMDK parser in [`pkg/fanal/vm/disk/vmdk.go`](https://github.com/aquasecurity/trivy/blob/main/pkg/fanal/vm/disk/vmdk.go) to expose a `SectionReader` interface. This streams each file inside the disk image to the standard analyzer pipeline—running package, OS, secret, and license detectors exactly as it would for a container filesystem. The results are assembled into `types.BlobInfo` structures and passed to configured output formatters.

## Scanning Remote AWS Targets

Scanning AMIs and EBS snapshots requires appropriate AWS permissions and authentication configuration.

### Required IAM Permissions

According to the documentation in [`docs/guide/target/vm.md`](https://github.com/aquasecurity/trivy/blob/main/docs/guide/target/vm.md), Trivy requires the following AWS actions:

- `ec2:DescribeImages`
- `ebs:ListSnapshotBlocks`
- `ebs:GetSnapshotBlock`

### Authentication and Region Configuration

Trivy uses the standard AWS SDK credential provider chain. Set `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` environment variables, or use IAM roles when running on EC2. Override the default region with the `--aws-region` flag, defined in [`pkg/commands/app.go`](https://github.com/aquasecurity/trivy/blob/main/pkg/commands/app.go) (lines 99-105) as part of the AWS flag group.

## Practical Scanning Examples

Scan a local VMDK file for vulnerabilities:

```bash
trivy vm --scanners vuln disk.vmdk

```

Scan an Amazon Machine Image by ID:

```bash
trivy vm ami:ami-0123456789abcdef0

```

Scan an EBS snapshot directly:

```bash
trivy vm ebs:snap-0123456789abcdef0

```

Specify a non-default AWS region:

```bash
trivy vm --aws-region ap-northeast-1 ami:ami-0a1b2c3d4e5f6g7h8

```

Optimize for speed when you only need vulnerability findings:

```bash
trivy vm --scanners vuln ebs:snap-0123456789abcdef0

```

## Optimizing for Repeated Scans

For scenarios requiring multiple scans of the same snapshot—such as CI/CD pipelines or compliance auditing—downloading the image locally reduces API costs and latency. Use **coldsnap** to fetch the snapshot blocks before scanning:

```bash
coldsnap download snap-0123456789abcdef0 disk.img
trivy vm ./disk.img

```

This approach bypasses the remote streaming implementation in [`pkg/fanal/artifact/vm/ebs.go`](https://github.com/aquasecurity/trivy/blob/main/pkg/fanal/artifact/vm/ebs.go) and [`ami.go`](https://github.com/aquasecurity/trivy/blob/main/ami.go), instead using the local file walker in [`pkg/fanal/walker/vm.go`](https://github.com/aquasecurity/trivy/blob/main/pkg/fanal/walker/vm.go).

## Summary

- **Trivy treats VM images as a distinct artifact type** (`vm`) with dedicated scanner services implemented in [`pkg/commands/artifact/scanner.go`](https://github.com/aquasecurity/trivy/blob/main/pkg/commands/artifact/scanner.go).
- **Three target modes are supported**: AWS AMIs (`ami:` prefix), EBS snapshots (`ebs:` prefix), and local VMDK files (no prefix), detected via `vm.NewArtifact` in [`pkg/fanal/artifact/vm/vm.go`](https://github.com/aquasecurity/trivy/blob/main/pkg/fanal/artifact/vm/vm.go).
- **AWS scanning requires specific IAM permissions** (`ec2:DescribeImages`, `ebs:ListSnapshotBlocks`, `ebs:GetSnapshotBlock`) and uses the standard AWS credential chain with optional `--aws-region` configuration.
- **The VM walker** (`walker.NewVM`) and **VMDK parser** ([`pkg/fanal/vm/disk/vmdk.go`](https://github.com/aquasecurity/trivy/blob/main/pkg/fanal/vm/disk/vmdk.go)) stream filesystem contents to Trivy's standard analyzers without requiring a running instance.

## Frequently Asked Questions

### What AWS permissions are required to scan an AMI with Trivy?

You need `ec2:DescribeImages` to resolve the AMI metadata, plus `ebs:ListSnapshotBlocks` and `ebs:GetSnapshotBlock` to read the underlying disk blocks. These permissions allow Trivy to stream the snapshot content through the VM walker without creating an EC2 instance.

### How does Trivy detect whether I am scanning a local file or an AWS resource?

In [`pkg/fanal/artifact/vm/vm.go`](https://github.com/aquasecurity/trivy/blob/main/pkg/fanal/artifact/vm/vm.go), the `detectType` function inspects the target string for prefixes. Targets starting with `ami:` route to `newAMI`, `ebs:` route to `newEBS`, and paths without prefixes route to `newFile` for local VMDK processing.

### Can I scan EBS snapshots from a different AWS region than my default configuration?

Yes. Use the `--aws-region` flag to specify any supported AWS region. This flag is part of the AWS flag group defined in [`pkg/commands/app.go`](https://github.com/aquasecurity/trivy/blob/main/pkg/commands/app.go) and overrides the default region in your AWS profile or environment variables.

### Why should I download an EBS snapshot with coldsnap before scanning?

Downloading with **coldsnap** first converts the remote snapshot into a local disk image. This eliminates repeated API calls to `ebs:GetSnapshotBlock` during iterative scans, reducing costs and latency when running Trivy multiple times against the same snapshot in CI/CD workflows.