CoursesInfrastructure as Code & automationAdvanced · Testing & secrets

Module & provider supply chain

Trust the code you did not write.

Advanced12 min · lesson 23 of 23

IaC runs code you mostly did not write — providers, community modules, Helm charts, base images — against your production infrastructure with high privilege, which makes it a supply-chain target just like application dependencies. A malicious or compromised module could exfiltrate your secrets during a plan, or quietly add a backdoor resource; a typosquatted provider could do the same. The supply-chain discipline from the CI/CD course applies directly to your infrastructure code: trust deliberately, pin everything, and verify what you can.

Pin and vet everything external

The foundation is pinning and provenance. Pin provider versions and commit the lock file (.terraform.lock.hcl), which also records the providers’ checksums so a tampered provider is rejected. Pin module versions to specific tags or commits, never a floating branch. Pin Helm chart versions and base image digests. And prefer sources you trust — official/verified providers and modules, your own internal registry for shared modules — over arbitrary community code, reviewing anything important before you run it. An unpinned, unvetted external module is untrusted code with production access.

terminal / config
# the lock file pins providers AND their checksums — commit it
$ terraform providers lock -platform=linux_amd64
$ cat .terraform.lock.hcl # version + h1: hashes; a tampered provider fails verification
# pin modules to an immutable ref, not a branch:
module "vpc" { source = "terraform-aws-modules/vpc/aws", version = "5.1.2" } # not "latest"

A private registry and least-privilege runs

At scale, teams run a private module registry (Terraform Cloud, or an internal one) as the single vetted source for shared modules, so everyone reuses reviewed code rather than pulling arbitrary sources — the infrastructure equivalent of a trusted internal package registry. And because IaC runs with powerful credentials, apply it with least privilege: scoped, short-lived credentials (OIDC), a locked-down runner, and separation between the plan (which needs read) and apply (which needs write) where you can. A compromised module can only do as much as the credentials the run holds.

The whole picture

Put the advanced section together and you have production-grade IaC: policy-as-code and scanners guard the code, GitOps applies it from Git with reviewed plans and no local credentials, drift detection keeps reality honest, testing proves modules work, secrets stay out of code and state is protected, and the supply chain is pinned and vetted. That is the difference between IaC as a convenience and IaC as a trustworthy, secure foundation — the same journey from "it works" to "it is safe and verifiable" that every track in this curriculum walks.

Your IaC has more power than most of your apps
It is easy to treat infrastructure modules as mere configuration, but IaC runs with the credentials to create, modify, and destroy your entire environment — a compromise here outranks most application compromises. So hold it to the highest supply-chain standard: pin and checksum providers (the lock file), pin and vet modules and charts, source from trusted/internal registries, run applies with least-privilege short-lived credentials on isolated runners, and review external code before it touches production. The blast radius of a malicious dependency is measured by what it can reach — and IaC can reach everything.