Scan a Whole Infrastructure as Code Repository with cnspec
Scan every Terraform, OpenTofu, CloudFormation, Bicep, Kubernetes, Helm, Kustomize, Ansible, and Dockerfile entry point in a repository with one cnspec command.
Most repositories hold more than one kind of infrastructure as code. A single service repo can carry Terraform for its cloud resources, a Helm chart for its deployment, and a Dockerfile for its image. Instead of adding one scan step per tool to your pipeline, point cnspec scan iac at the root of the repository. cnspec walks the tree, finds every entry point it recognizes, and scans each one with the same connector you would use on its own, such as cnspec scan helm or cnspec scan cloudformation.
This page is part of scanning your supply chain with cnspec. If you're new to cnspec, start with the Quickstart to install cnspec and run your first scan.
Experimental
The iac provider is experimental. Its resources, discovery names, and flags may change between
releases. It requires cnspec 14.0 or later.
Prerequisites
To scan a repository with cnspec, you must have:
- cnspec 14.0 or later installed on your workstation or CI runner
- A directory of infrastructure as code files to scan
cnspec reads the files directly. None of the tools it scans for (Terraform, OpenTofu, Helm, Kustomize, Ansible, Bicep, or Docker) need to be installed on the machine that runs the scan.
Scan a repository
Scan the current directory:
cnspec scan iac .cnspec reports one asset for the repository itself, plus one asset for every entry point it found in it. Each entry point asset is the same asset the tool's own connector produces, so a Helm chart found by cnspec scan iac is scanned by the same policies as one scanned with cnspec scan helm.
Terraform and OpenTofu are opt-in
A plain cnspec scan iac . does not scan Terraform or OpenTofu configurations. Add them to
--discover. For a repository that uses Terraform:
cnspec scan iac . --discover auto,terraformFor a repository that uses OpenTofu, or is moving from Terraform to OpenTofu, name both:
cnspec scan iac . --discover auto,opentofu,terraformTo learn why both names are needed, read Scan Terraform and OpenTofu together.
You can also point cnspec at a single file. cnspec then scans only that file and ignores the rest of the directory.
What cnspec detects
cnspec decides which tool owns a file by its name, then asks that tool's provider to confirm. A file that a tool's pattern matches but that the tool doesn't recognize as its own (for example, a YAML file that is not a Kubernetes manifest) is skipped silently.
| Tool | --discover name | Matching files | In auto | Scanned as |
|---|---|---|---|---|
| Ansible | ansible | ansible.cfg, inventory, roles/*/tasks/main.yml, *.yml, *.yaml | Yes | The directory |
| Azure Bicep | bicep | *.bicep, *.bicepparam | Yes | The directory |
| AWS CloudFormation | cloudformation | *.yaml, *.yml, *.json, *.template | Yes | Each template file |
| Dockerfiles | dockerfile | Dockerfile, Dockerfile.*, *.Dockerfile, *.dockerfile | Yes | Each Dockerfile |
| Helm charts | helm | Chart.yaml | Yes | The chart directory |
| Kubernetes manifests | k8s | *.yaml, *.yml | Yes | The directory |
| Kustomize overlays | kustomize | kustomization.yaml, kustomization.yml, Kustomization | Yes | The directory |
| OpenTofu | opentofu | *.tofu, *.tofu.json | No | The directory |
| Terraform | terraform | *.tf, *.tf.json | No | The directory |
The terraform and opentofu names find directories by file extension only, so an OpenTofu project written entirely in .tf files is found by terraform, not opentofu. To learn how the two names work together, read Scan Terraform and OpenTofu together.
To learn more about how each tool's files are read, see its guide: Ansible, Bicep, CloudFormation, Dockerfiles, Helm, Kubernetes manifests, Kustomize, OpenTofu, and Terraform.
Choose which tools to scan
--discover takes a comma-separated list of the names in the table above, plus auto:
| Value | What it scans |
|---|---|
| (flag not set) | Every tool marked In auto in the table above |
auto | The same set as leaving the flag unset |
auto,terraform | The default set plus Terraform |
auto,opentofu,terraform | The default set plus OpenTofu and Terraform, reading directories that hold both as OpenTofu |
auto,terraform,opentofu | The default set plus Terraform and OpenTofu, reading directories that hold both as Terraform |
terraform,helm | Only Terraform configurations and Helm charts |
An unknown name stops the scan with an error that lists every valid value.
--discover all also exists, but it first offers the root of the repository to every tool. A tool
that claims the root then skips everything below it, so all can report fewer assets than naming
the tools yourself. Use auto,opentofu,terraform or auto,terraform,opentofu to scan everything.
Scan Terraform and OpenTofu together
Terraform and OpenTofu share one configuration language, and OpenTofu reads .tf files exactly the way Terraform does. From the files alone, cnspec often can't tell which tool a directory is applied with, so it doesn't guess. You tell it by naming terraform, opentofu, or both in --discover.
Which directories each name finds
Each name finds a directory by the files in it:
| The directory holds | Found by terraform | Found by opentofu |
|---|---|---|
Only .tf and .tf.json files | Yes | No |
Only .tofu and .tofu.json files | No | Yes |
Both .tf flavored and .tofu flavored files | Yes | Yes |
Most OpenTofu projects keep their .tf files, so most OpenTofu directories are found only by terraform. That is why a repository that uses OpenTofu needs both names: opentofu alone skips every directory that has no .tofu file. A directory found by terraform is read the way Terraform reads it, which for a directory with no .tofu files is also the way OpenTofu reads it. cnspec reports it as a Terraform HCL asset.
Directories that hold both
A directory that holds both .tf and .tofu files produces one asset, not two. The name you list first in --discover decides how cnspec reads it:
--discover auto,opentofu,terraformreads it the way OpenTofu does: a.tofufile replaces the.tffile with the same name (main.tofureplacesmain.tf). cnspec reports an OpenTofu HCL asset.--discover auto,terraform,opentofureads it the way Terraform does:.tofufiles are ignored. cnspec reports a Terraform HCL asset.
List first the tool that actually applies the directory, so cnspec checks the same configuration that tool deploys. The order doesn't matter for directories that only one of the names finds.
Example: migrate from Terraform to OpenTofu
A team is moving a repository from Terraform to OpenTofu one module at a time. Midway through, the repository looks like this:
infra/
├── network/
│ └── main.tf # not migrated yet
├── storage/
│ ├── main.tf # kept so Terraform can still apply the module
│ └── main.tofu # adds OpenTofu state encryption
└── logging/
└── main.tofu # new module, written for OpenTofuThe team now applies all three modules with tofu. To scan every module the way OpenTofu applies it, list opentofu first and keep terraform so network is still found:
cnspec run iac infra --discover auto,opentofu,terraform -c "iac.detections { tool path }"detections: [
0: {
tool: "opentofu"
path: "logging"
}
1: {
tool: "terraform"
path: "network"
}
2: {
tool: "opentofu"
path: "storage"
}
3: {
tool: "terraform"
path: "storage"
}
]storage is detected by both names but becomes a single asset. Scanning the repository reports these assets:
cnspec scan iac infra --discover auto,opentofu,terraform| Directory | Asset | Files cnspec reads |
|---|---|---|
logging | OpenTofu HCL directory logging | main.tofu |
network | Terraform HCL directory network | main.tf |
storage | OpenTofu HCL directory storage | main.tofu (replaces main.tf) |
Compare the other choices for the same repository:
--discover auto,opentofuskipsnetwork, because it has no.tofufile.--discover auto,terraformskipsloggingand readsstoragefrommain.tf, so the state encryption settings inmain.tofuare never checked.--discover auto,terraform,opentofufinds every module but readsstoragefrommain.tf, the way Terraform would.
Keep both names in --discover after the migration too: any module you leave in .tf files is still found only by terraform.
Mondoo's built-in Terraform policies select Terraform HCL assets, so they don't evaluate the OpenTofu HCL assets in this example. To learn how to write checks that cover both, read Policies for OpenTofu assets.
Skip directories
By default, cnspec skips these directories wherever they appear in the tree: .git, .terraform, .terragrunt-cache, .venv, node_modules, vendor, target, and dist.
--iac-ignore replaces that list. It does not add to it, so include the defaults you still want skipped:
cnspec scan iac . --iac-ignore .git,.terraform,node_modules,examplesTo scan vendored code as well, pass an empty list:
cnspec scan iac . --iac-ignore ""Preview what a scan will find
To see which entry points cnspec detects without running any policies, query the iac resource:
cnspec run iac . --discover auto,terraform -c "iac.detections { tool path error }"detections: [
0: {
error: ""
tool: "dockerfile"
path: "Dockerfile"
}
1: {
error: ""
tool: "helm"
path: "charts/api"
}
2: {
error: "rpc error: code = Unknown desc = cannot load Chart.yaml: error converting YAML to JSON: yaml: line 2: did not find expected ',' or ']'"
tool: "helm"
path: "charts/broken"
}
3: {
error: ""
tool: "terraform"
path: "terraform"
}
]path is relative to the directory you scanned. If a tool recognizes an entry point but can't read it, such as a Helm chart with a malformed Chart.yaml, cnspec records the error on that detection and keeps walking the tree. The rest of the repository is still scanned.
A detection that reports an error does not produce an asset and does not change the scan's exit
code. If a malformed file must fail your pipeline, check iac.detections for errors in a separate
step.
To learn about every field, read the iac resource reference.
Scan in CI/CD
cnspec scan iac is designed for CI/CD: one step scans every entry point in the checked-out repository, and new charts, templates, or modules are picked up without editing the pipeline.
cnspec scan iac . \
--discover auto,terraform \
--risk-threshold 90 \
--output junit --output-target cnspec-junit.xml--discover auto,terraformadds Terraform to the default set. If the repository uses OpenTofu, use--discover auto,opentofu,terraforminstead.--risk-threshold 90fails the job with exit code 1 if any asset has a critical risk (90 or higher). To learn how to choose a threshold, read Exit code handling.--output junit --output-target cnspec-junit.xmlwrites one JUnit test suite per asset, which most CI systems can display as test results. For tools that read SARIF, use--output sarifinstead. To learn about every format, read Report Results.- Set
MONDOO_CONFIG_BASE64to your Mondoo service account credentials to report the results to Mondoo Platform, or add--incognitoto keep them local.
The official mondoo/cnspec container image runs cnspec as its entrypoint, so you can use mondoo/cnspec:14 as the job image on any CI system that runs containers.
For complete pipeline examples, see the guide for your CI system:
Scan options
| Option | Description |
|---|---|
--asset-name | Override the asset name |
--annotation | Add an annotation to the asset (key=value) |
--incognito | Run in incognito mode (do not report results to Mondoo Platform) |
-o, --output | Set the output format (compact, csv, full, hdf, json, junit, ocsf-json, ocsf-parquet, report, sarif, summary, yaml) |
-f, --policy-bundle | Path to a policy file (local path, s3:// URI, or http(s):// URL) |
--policy | Specify policies to execute (requires --policy-bundle) |
--risk-threshold | Exit with status 1 if any risk meets or exceeds this value (0-100) |
To gate a CI/CD pipeline, combine --risk-threshold with a report file, for example --risk-threshold 90 --output junit --output-target cnspec-junit.xml. 90 fails the job only on critical risks, 70 also fails on high risks, and 40 also fails on medium risks. To scan every infrastructure as code entry point in a repository in one step, use cnspec scan iac. For complete pipeline examples, read Integrate Mondoo with CI/CD Platforms.
In addition to the options above, cnspec scan iac accepts --discover and --iac-ignore, described earlier on this page.
Learn more
- Integrate Mondoo with CI/CD platforms
- Report scan results
- iac resource reference: the
iac,iac.detection, andiac.sourceresources