An infrastructure repository usually depends on at least seven kinds of thing: Terraform modules, providers, Helm charts, container images, tool plugins, remote manifest bases and the tools themselves. Few of them sit in a package lock file, so a normal dependency scan can miss them. List each kind by hand once, then automate.
Why these get missed
Application teams know their dependencies live in package manifests. Infrastructure code spreads them across file types, each with its own pinning rules. Some are fetched at init time, some at render time, some only on a CI runner. A scanner that reads only application lock files will report a clean result on a repository full of unpinned sources.
The seven places
| Place | Where it is declared | Pinning mechanism |
|---|---|---|
| Terraform and OpenTofu modules | source in module blocks | Registry version constraint, or ref on Git sources |
| Providers | required_providers | Constraint plus the lock file |
| Helm charts and subcharts | Chart.yaml dependencies, helm_release | Exact version, Chart.lock, digest for OCI |
| Container images | Values files, manifests, Terraform resources | Digest |
| Tool plugins | TFLint config, Packer required_plugins, Helm plugins | Exact version, signature checks |
| Remote manifest bases | kustomize resources URLs, GitOps application sources | ref with full commit, or digest |
| The tools themselves | CI setup steps, version files | Pinned versions |
Terraform's module documentation shows why the first row needs care: the version argument only works for registry modules, while Git sources follow the default branch unless a ref is given.
How to inventory each
- Modules and Git sources. Search .tf files for source lines. Mark any Git or HTTP source without a ref.
- Providers. Read required_providers and confirm the lock file is committed. Note any override in a CLI configuration on your runners.
- Charts. Read each Chart.yaml dependencies block, and any helm_release resources. Remember that all subcharts load by default, and a condition only changes loading.
- Images. Search values files, rendered manifests and Terraform resources for image references. Mark any without a digest.
- Plugins. List TFLint plugin blocks, Packer required_plugins and installed Helm plugins on build hosts.
- Remote bases. Search for resources entries that start with a URL, and Argo CD or Flux sources. Record their revision or reference.
- Tools. Check CI for setup steps that install the Terraform, Helm, kustomize or Packer versions, and whether they are pinned.
Keep the result in a simple table in the repository: dependency, kind, location, pinned how, owner. That table is the beginning of an SBOM for your infrastructure.
Pinning strength at a glance
Moving from weakest to strongest: no reference at all, a branch, a tag you do not protect, a semver range, an exact version, a protected tag, a commit hash or digest. Aim for the last two for production.
Updates then become deliberate. Bots such as Renovate cover many of these file types, as its Terraform and Helm manager documentation shows. See what can Renovate update in Terraform and Helm repositories.
Make it routine
Add a CI job that fails on new unpinned sources. Run a quarterly review of the inventory table. Assign an owner to every entry, so when an advisory lands you know whom to ask. Pair this with a monitoring step, so new findings in already deployed components reach you.
Where a scanner fits
Safeguard's asset discovery, SBOM generation and dependency scanning are built to give you this inventory, and policy gates can enforce the pinning rules on each pull request. Confirm which of the seven file types your scanner reads, and fill gaps by hand. You can run a free scan at gold.safeguard.sh/scan.
Try it yourself
Click through it at your own pace, or open it full screen.
Compare the inventory it builds with your own seven-row table, and note which rows a scanner would not fill in for you.
Quick check
Does a clean application scan cover my Terraform and Helm dependencies?
Not necessarily. Modules, providers, charts, images and plugins are declared in infrastructure files, so confirm your scanner reads those file types.
What is the quickest improvement?
Find every dependency source that has no pinned reference, such as Git modules without ref or images without digests, and pin those first.
Sources
- Use modules in your configuration, HashiCorp
- Charts, Helm documentation
- Images, Kubernetes documentation
- Terraform manager, Renovate documentation
Last reviewed: 19 October 2026.