How to Fix Terraform Provider Signature Verification Failed: Certificate Expired
Threat/Impact Level: HIGH | Exploitability/Downtime Risk: HIGH | Time to Fix: 10 mins
TL;DR
- What broke: HashiCorp's GPG signing certificate used to verify provider binaries has expired;
terraform initandterraform providers mirrorabort with a signature verification error, blocking all provider installs. - How to fix it: Flush the local plugin cache, import the current HashiCorp GPG public key (Key ID
72D7468F), and ensure yourterraformbinary is ≥ 1.4.x which ships with the refreshed keyring. - Fast path: Use our Client-Side Sandbox below to auto-refactor your
provider_installationblock and.terraformrcwithout leaking registry tokens or private module paths.
The Incident (What Does the Error Mean?)
Raw error output from terraform init:
│ Error: Failed to install provider
│
│ Error while installing hashicorp/aws v5.x.x: the current package for
│ registry.terraform.io/hashicorp/aws 5.x.x doesn't match any of the
│ checksums previously recorded in the dependency lock file.
│
│ HashiCorp release signature verification failed:
│ certificate expired: current time 2024-xx-xxTxx:xx:xxZ is after
│ 2024-xx-xxTxx:xx:xxZ
Immediate consequence: terraform init hard-fails. No provider is installed or upgraded. Every pipeline stage that calls init — including plan, apply, and drift-detection jobs — is dead. In airgapped or Terraform Enterprise environments using a local mirror, this can silently block the entire platform team until the keyring is manually refreshed.
The Attack Vector / Blast Radius
This is not a benign cert rotation annoyance. Here is the actual risk surface:
Supply-chain integrity gap. The GPG signature on provider zips is the only cryptographic guarantee that the binary you are about to execute inside your AWS/GCP/Azure account is the one HashiCorp shipped. When the certificate expires and your toolchain is misconfigured to skip verification instead of fail, you have silently disabled the entire supply-chain check. A compromised registry mirror or a MITM on an internal Artifactory proxy can now serve a backdoored provider binary — hashicorp/aws with exfiltration code — and Terraform will execute it with your AWS_ACCESS_KEY_ID in scope.
Blast radius by environment:
| Scenario | Risk |
|---|---|
Developer workstation skips verification via skip_signature_verification workaround |
Full credential exfiltration risk on next apply |
CI/CD runner patched with --insecure flag to unblock pipeline |
Every plan/apply job runs unverified binaries |
| Terraform Enterprise / TFE airgapped mirror not refreshed | Entire organization blocked or running on stale, unverified cache |
The cascading failure: Teams under pressure to unblock pipelines add skip_signature_verification = true to their .terraformrc. This config gets committed. It propagates across teams. Six months later, nobody remembers why it's there, and it never gets removed.
How to Fix It
Step 1 — Purge the stale plugin cache
# Nuke the local provider cache. This forces a clean re-download and re-verification.
rm -rf ~/.terraform.d/plugins
rm -rf .terraform/providers
rm .terraform.lock.hcl
Step 2 — Import the current HashiCorp GPG signing key
# HashiCorp's current release key. Verify the fingerprint out-of-band.
curl -fsSL https://apt.releases.hashicorp.com/gpg | gpg --import
# Confirm fingerprint: E8A0 32E0 94D8 EB4E A189 D270 DA41 8C88 A321 9F7B
gpg --fingerprint 72D7468F
Step 3 — Upgrade Terraform CLI
Terraform ≥ 1.4.x ships with the refreshed embedded keyring. If you cannot upgrade immediately, the GPG import above is sufficient for the short term.
# macOS
brew upgrade terraform
# Linux (tfenv)
tfenv install latest
tfenv use latest
# Verify
terraform version
Basic Fix — .terraformrc provider_installation block
# ~/.terraformrc
provider_installation {
- filesystem_mirror {
- path = "/opt/terraform/providers"
- include = ["registry.terraform.io/*/*"]
- }
- # WARNING: This was added to unblock CI. REMOVE THIS.
- direct {
- exclude = []
- }
+ filesystem_mirror {
+ path = "/opt/terraform/providers"
+ include = ["registry.terraform.io/hashicorp/*"]
+ }
+ direct {
+ include = ["registry.terraform.io/hashicorp/*"]
+ }
}
Enterprise Best Practice — Enforce signature verification in Terraform Enterprise / Atlantis
For airgapped TFE or a self-hosted registry mirror (Artifactory, Nexus), you must re-sign mirrored provider zips with your internal CA and register the public key in TFE's GPG key store. Never use skip_signature_verification.
# providers.tf — required_providers block
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
- version = ">= 4.0"
+ version = "~> 5.50" # Pin to a tested minor, not a floor. Prevents silent major upgrades.
}
}
+
+ # Lock file must be committed to VCS. Never .gitignore .terraform.lock.hcl
}
# For Terraform Enterprise: register the new GPG key via API, not manually.
# BAD: Manual key import on one node only.
- curl --header "Authorization: Bearer $TFE_TOKEN" \
- --request POST \
- --data '{"data":{"type":"gpg-keys"}}' \
- https://tfe.internal/api/registry/private/v2/gpg-keys
# GOOD: Automate key rotation via your secrets pipeline (Vault + Terraform TFE provider)
+ resource "tfe_registry_gpg_key" "hashicorp_current" {
+ organization = var.tfe_org
+ ascii_armor = file("${path.module}/keys/hashicorp-current.asc")
+ }
💡 Tired of pasting proprietary configs into ChatGPT? Generic AI tools log your company's ARNs, DB strings, and private keys. StackEngine is a zero-backend, pure Client-Side WASM utility. Drop your failing config into the sandbox above. We redact your secrets locally in the browser and auto-generate the refactored code using your own API key.
Prevention in CI/CD
1. Pin and verify the Terraform binary in CI
# .github/workflows/terraform.yml
- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: "1.8.5" # Explicit pin. Never use 'latest' in prod pipelines.
terraform_wrapper: false
2. Checkov policy — block skip_signature_verification
# checkov/custom/check_no_skip_sig_verification.py
from checkov.common.models.enums import CheckResult, CheckCategories
from checkov.terraform.checks.resource.base_resource_check import BaseResourceCheck
# Scan .terraformrc files in your repo for the dangerous flag.
# Integrate into pre-commit and CI gate.
Or use a simpler grep gate in CI:
# Fail the pipeline if anyone committed the bypass flag.
if grep -r "skip_signature_verification" .; then
echo "FATAL: skip_signature_verification found in repo. Remove it."
exit 1
fi
3. Automate GPG key freshness check
# Add to your weekly platform health cron job.
KEY_EXPIRY=$(gpg --list-keys --with-colons 72D7468F | grep '^pub' | cut -d: -f7)
NOW=$(date +%s)
if [ "$KEY_EXPIRY" -lt "$NOW" ]; then
echo "ALERT: HashiCorp GPG key expired. Rotate immediately."
# Page on-call via PagerDuty/Opsgenie webhook here.
fi
4. OPA / Conftest policy for provider lock file
# policy/terraform_lock.rego
package terraform.lockfile
deny[msg] {
# Ensure lock file exists and is not empty — catches teams deleting it to "fix" checksum errors.
not input.provider
msg := "DENY: .terraform.lock.hcl is missing or has no provider entries. Do not delete the lock file to bypass checksum errors."
}
Run in CI: conftest test .terraform.lock.hcl --policy policy/