Terraform providers rebuilt from source, patched and signed
The container your pipeline runs in was rebuilt from source this morning, scanned, signed and shipped with an SBOM. A second later it ran terraform init, downloaded a statically linked Go binary from a public registry, checked one signature against a key the registry handed it, and gave that binary your cloud credentials. Nobody rebuilt that binary. Nobody but the maintainer can.
If your platform team moved to Chainguard, or to Wolfi, or to any rebuilt-from-source image catalogue, you did it to stop waiting. A CVE in a library inside a base image used to mean waiting for a distribution to package the fix, then for whoever maintained the image to rebuild on top of it, then for the next release train to carry it to you. Chainguard's answer was to become the vendor for everything in the image: build it all from source, patch at the dependency, rebuild daily, sign the result, ship an SBOM, and put a clock on remediation. Their own phrasing is that customers do not wait for a patch from a vendor because they are that vendor for all the software in the image. They have since done the same for Java and Python libraries.
Terraform providers have the identical exposure and none of that machinery. A provider is one Go binary with every dependency compiled in. When a vulnerability lands in golang.org/x/crypto or grpc-go, every provider version that vendors the affected module is affected, and the only fix path runs through the upstream maintainer, on their schedule, in a release that also carries whatever else changed that month. Your image scanner reports the runner clean and says nothing about the binary that just ran inside it with an administrator role.
This page is about closing that gap with the same pattern. It says where the pattern carries over directly, where a provider is a different problem from an image, and where Terramantle is today against where it is going before general availability.
Why a provider is not an image
I'd like to say Terramantle is Chainguard for providers and leave it there. The slogan is right about the intent and wrong about the mechanics, and the mechanics are where the difficulty lives.
There is nothing to swap. An image is a composition. A package manager installed a set of packages into a filesystem, and patching one of them means replacing that package and rebuilding the layer. A provider is the output of a single go build. Its dependencies are not files in it; they are compiled into it. The only way to change one is to change go.mod and recompile the entire thing from the upstream source. For hashicorp/aws that is one of the largest Go modules anyone compiles, and what it took to do that reliably is its own page.
The version number is not ours. Chainguard owns the tags on its images. A provider's version belongs to upstream. A patched build cannot call itself 6.3.3, because upstream's 6.3.3 exists and is signed by them, so a Terramantle revision is published as 6.3.3-0.0.1, a prerelease of the base. Terraform and OpenTofu drop prereleases from range constraints on the client, which means ~> 6.3 can never select it. That single fact shaped the delivery mechanism, below.
The client dictates the signature. A container runtime can verify a Sigstore signature if you tell it to. tofu init verifies one thing: a SHA256SUMS file and a detached OpenPGP signature over it, against keys the registry protocol supplies. Whatever Terramantle signs has to be that shape or nothing verifies it. So the provenance format is set by the consumer, not chosen by me.
The pattern, stage by stage
With those differences stated, the shape of the solution is the same shape. Each row is one stage of the image pattern and what the equivalent is for a provider in Terramantle.
| Stage | The image pattern | A Terramantle-built provider |
|---|---|---|
| Be the vendor | Every package in the image built from source by the image publisher | The upstream release tag cloned into a fork Terramantle owns; every revision is one squashed commit whose parent is the upstream tag commit |
| Patch at the dependency | Bump the vulnerable package, rebuild the image | Bump the vulnerable Go module to the scanner's fix version, same major only, then smoke-build and run govulncheck. If either fails, the build fails. There is no fallback to an unpatched build |
| Build in a sandbox | A hardened build system the publisher controls | An ephemeral gVisor pod, non-root, read-only root filesystem, no signing key in the image, GOTOOLCHAIN=local, -mod=readonly, checksum database on, egress allow-listed to the module proxy and the git host. Only go build ever runs |
| Gate before publish | Scan the built image | Four gates outside the builder: Semgrep on the source, an LLM intent review that fails closed, ClamAV over the built zips with a seven-day database freshness check, and a go.sum pin check with govulncheck and a dependency-graph audit |
| Sign | A signature over the image digest | A separate hasher assembles SHA256SUMS from the built zips; a separate signer, the only container with the key, produces the detached OpenPGP signature tofu init verifies |
| SBOM | A bill of materials published with the image | An SPDX SBOM per provider version, stored and re-evaluated against the vulnerability database daily so a new advisory surfaces without a rebuild |
| Serve | A registry you point FROM at | A registry you point required_providers at. With substitution on, a request for the upstream base version is answered with the latest published, scanned, platform-complete patched revision, and the lock file records its hashes |
The one row with no image equivalent is the last one. An image publisher can ship a new tag and you pull it. A patched provider has to be delivered to a constraint that will never ask for it by name, which is why substitution exists, and why every reason substitution does not apply falls through to the upstream mirror. It can swap bytes the org was already entitled to pull. It can never refuse.
What a patch waits on
The image pattern's cadence is a daily rebuild. A provider rebuild is too expensive to run on a timer for its own sake, and it does not need to. The thing a patched provider waits on is the fixed version of the dependency. The day a fixed x/crypto or grpc-go release exists on the module proxy, the scanner's finding carries a fixed_version, and that is the patch manifest's target. Nothing in the chain waits on the provider maintainer.
Detection runs daily. Every scanned provider version has its SPDX SBOM re-evaluated against the current vulnerability database, so a newly published CVE shows up against the versions that vendor the module without anyone cloning anything. The patch then starts from the upstream tag every time, never on top of a previous patched tree, so revisions never compound and the diff against upstream is always one commit. After the build, the comparison endpoint shows what the patch fixed, what remains and anything it introduced, with the fork repository, both commit SHAs and a diff URL.
Two statuses matter more than the rest. A major-version bump is reported and never applied, because it can change provider behaviour, so a fix that only exists in a new major of a dependency shows as nothing_to_patch until upstream moves. And fleet-wide scheduling is paused as of the review date at the foot of this page, for capacity reasons recorded in the worker's configuration, so today a patch runs when the portal or the API asks for one rather than on its own.
What the signature says, and what holds the key
An upstream signature says the publisher's key signed these checksums. A Terramantle signature says something narrower and more useful: compiled by Terramantle, from a named commit, and passed the four gates. The pin step hashes one source tarball that the compiler and every source-level gate consume, so the bytes scanned are the bytes built, and the signer cannot start until the gates have passed. It does not say "safe". Static analysis, an LLM review and an anti-malware scan each have false negatives, and the provenance page goes through what is and is not inside the claim.
The key is where Terramantle is behind the image vendors today, and I'd rather say so than have a reviewer find it. The signing key is a software RSA-4096 key, sealed into the cluster and imported into a memory-backed keyring at start, with a fingerprint assertion so a wrong key cannot sign. The signer's documentation calls that a deliberate step down from the hardware design, and it means a suspected compromise requires an out-of-band revocation announcement, not rotation alone. Moving the key into a hardware module is the step before general availability, not an item on a roadmap. Until it has happened this page will say software key.
SLA and SLSA
Chainguard puts a clock on remediation, and a security programme that has bought images on that basis will ask the same of anything else that runs in the pipeline. On Business, a patch is attempted as soon as the fix exists, with no contract around it. On Enterprise, two optional add-ons close the gap: a contracted remediation window, and a signed SLSA provenance statement for each built version.
| Severity | Window from fix available to patched revision served |
|---|---|
| Critical | 7 days |
| High | 14 days |
| Everything else | 28 days |
The window starts when a fixed dependency version is published, not when the CVE is, because there is nothing to build until then. A fix that only exists behind a major-version bump is out of scope for the same reason it is out of scope for the patch step: shipping it would change what the provider does.
What this does not do
It does not patch the provider's own code. The patch is a dependency bump in go.mod, so a vulnerability in the provider's own source waits for upstream like any other. It does not apply major-version bumps. It does not sign modules, which are not signed at all. Outside the Enterprise add-on there is no SLSA statement, no in-toto layout and no Sigstore signature, because the client verifies OpenPGP over checksums and nothing else. The signing key is a software key until the hardware step lands. The fleet scheduler is paused as of the review date. And a rebuilt provider does nothing for the image it runs in, which is why this is the second half of a pipeline's supply chain rather than a replacement for the first. For the delivery mechanics in full, see CVE-patched providers.
Rebuilt provider FAQ
Does this replace Chainguard images?
No. They cover different artefacts in the same pipeline. The image is the environment your CI job runs in; the provider is a binary that job downloads after it starts, and no image hardening reaches it. Use a rebuilt image for the runner and a registry that rebuilds providers for what the runner pulls.
What do I change in my Terraform?
Point required_providers, or a provider mirror block, at your org's registry host and run tofu init or terraform init as usual. The download document carries the checksums, the signature and the signing key, so the CLI's ordinary verification is the only verification. When substitution is on, the lock file records the patched revision's hashes.
Can I see exactly what a patched build changed?
Yes. Every patched revision is one squashed commit whose parent is the upstream tag commit, in a fork Terramantle owns. The comparison endpoint returns the fork repository, the tag, both commit SHAs and a diff URL, plus the finding-level diff: what the patch fixed, what remains and anything it introduced.
Is there a remediation SLA?
On Business, a patch is attempted as soon as the scanner reports a fixed dependency version, with no contract around it. On Enterprise, a contracted window of 7 days for critical, 14 for high and 28 for everything else is an optional add-on, as is a signed SLSA provenance statement for each built version.
Does it work for OpenTofu and for providers that are not HashiCorp's?
Yes to both. OpenTofu and Terraform share the registry protocol and the signature format, so one build serves both. Any provider the registry can mirror can be built, and it goes through the same gates whoever maintains it.
Rebuilt, patched, gated, signed, served.
Terramantle-built and CVE-patched providers are on the Business tier. A contracted remediation window and SLSA provenance are optional add-ons on Enterprise.
Last reviewed
Terramantle is a private Terraform and OpenTofu registry. See pricing or read the FAQ.