Skip to main content
RunBook Academy

TerraformVI · Providers and the Provider EcosystemProduction Terraform

Provider Sources and Registries

Foundation⏱ ~12 minbash

What you'll learn

  • Read and write a provider source address in the canonical three-part form
  • Distinguish the public registry, a private registry, and a filesystem mirror
  • Configure `provider_installation` in the CLI config to redirect sources
  • Recognise the trust difference between official and community providers
  • Diagnose the common source-related failure modes

Prerequisites

None — start here.

Verified against Terraform CLI 1.9.x · OpenTofu 1.7.x · HCL 2.0 · bpg/proxmox provider 0.66+ · hashicorp/local provider 2.5+ · hashicorp/null provider 3.2+ · hashicorp/random provider 3.6+ · hashicorp/http provider 3.4+ · Ubuntu 24.04 LTS · Debian 12 (Bookworm) · 2026-08-13

Not yet marked complete on this device.

A provider source is the address Terraform uses to fetch a provider binary. The address is more than a name. It tells Core which registry to talk to, which namespace to look in, and which type to download. Get the address wrong and the init fails. Get the trust wrong and the binary runs in your estate. The lesson teaches the address format, the kinds of sources Terraform supports, and the production trade-offs between them.

The source address

Every provider declaration includes a source. The canonical form is three parts:

[<HOSTNAME>/]<NAMESPACE>/<TYPE>

Examples:

terraform {
  required_providers {
    aws        = { source = "hashicorp/aws" }
    azurerm    = { source = "hashicorp/azurerm" }
    github     = { source = "integrations/github" }
    mycompany  = { source = "mycorp.example.com/mycompany/internal" }
    local      = { source = "hashicorp/local" }
  }
}
  • HOSTNAME (optional). Defaults to registry.terraform.io, the public registry. A different hostname selects a private registry.
  • NAMESPACE. A namespace owned by an organisation. hashicorp/* is the official set; integrations/github is the GitHub-maintained provider; mycompany/* is internal.
  • TYPE. The provider name itself.

The HOSTNAME/NAMESPACE/TYPE triplet is the unique key. Two providers in different namespaces can share the same TYPE (hashicorp/aws and mycorp/aws-experimental are different providers).

The four kinds of sources

Terraform 1.9 supports four kinds of provider sources:

1. The public registry. registry.terraform.io. The default. Hosts hashicorp/* plus third-party providers. Free to use, signed, versioned, and documented. Every CI runner in the world can reach it. No auth is required for download.

2. A private registry. A Terraform-native registry running inside your organisation. Examples include HashiCorp’s self-hosted Terraform Cloud private registry, plus open-source options like terustry and boring-registry. A private registry is a real Terraform-native service: it speaks the discovery protocol, signs binaries with a configurable GPG key, and exposes an HTTP API Terraform can consume.

3. A network mirror. A simple HTTP(S) endpoint that mirrors the public registry’s protocol. Tools like JFrog Artifactory, Sonatype Nexus, and Cloudsmith implement this. A network mirror is a cache and a control point, not a full registry. The downside: it usually does not sign binaries.

4. A filesystem mirror. A local directory layout that mirrors the registry structure. Used for air-gapped environments and offline workstations.

A host can use any combination. The CLI config chooses.

Configuring where Terraform looks

The CLI config file (~/.terraformrc for the user, /etc/terraformrc for the host) controls the installation method:

# CONFIGURATION: ~/.terraformrc
provider_installation {
  # Method 1: a private registry for `mycorp/*`,
  # the public registry for everything else.
  network_mirror {
    url = "https://artifactory.mycorp.example.com/terraform/"
    include = ["mycorp/*"]
  }
  direct {
    exclude = ["mycorp/*"]
  }
}

# Method 2: a filesystem mirror for everything.
# provider_installation {
#   filesystem_mirror {
#     path = "/opt/terraform-mirror"
#   }
#   direct {
#     # The default fallback when the mirror has nothing.
#   }
# }

Two important behaviours:

  • First match wins. Terraform walks the methods in order. The first that claims the provider and serves the binary is the one used.
  • include and exclude are optional. With no filters, a method handles every provider. With filters, the method handles only the listed sources.

The filesystem mirror

For air-gapped production environments, a filesystem mirror is the standard. The layout is the same as the public registry:

/opt/terraform-mirror/
└── registry.terraform.io/
    └── hashicorp/
        └── aws/
            ├── 5.80.0.json
            └── terraform-provider-aws_5.80.0_linux_amd64.zip

Populate it with a script that periodically pulls from the public registry on a host that has network access. The metadata JSON describes the available versions and platforms. The .zip is the signed binary bundle.

To use the mirror:

# CONFIGURATION: ~/.terraformrc
provider_installation {
  filesystem_mirror {
    path = "/opt/terraform-mirror"
  }
  direct {}  # Used only as a fallback.
}

Official versus community providers

The public registry hosts both hashicorp/* providers and community-maintained providers. The trust posture is different:

NamespacePublisherSigningCadenceProduction posture
hashicorp/*HashiCorpYes (HashiCorp key)PredictableDefault for AWS, GCP, Azure, Vault, etc.
integrations/*Named partner (GitHub, MongoDB, Datadog)Yes (partner key)PredictableDefault for the partner’s own service
*/*Third partyOptionalVariableVet before use

For a production estate:

  • Default to hashicorp/* and integrations/* for the services you actually use. AWS, Azure, GCP, Vault, Kubernetes, GitHub, Datadog all have first-class providers.
  • Treat every third-party provider as a supply-chain dependency. Pin the version. Read the changelog. Confirm the namespace owner is who you think it is. Confirm the provider is signed.
  • Mirror what you can. A private registry or a network mirror gives you a single control point for the supply chain. A gitleaks rule against provider source addresses is not enough on its own.

Production failure modes

Five failure modes recur:

1. Typo in the source address. The most common cause of “provider not found”. hashicorp/aws is correct; hashicorp/aws-sdk is a different (non-existent) provider. The fix is to read the source address back from the public registry page, not from memory.

2. Mirror outage. A network mirror is down. Terraform falls back to direct if configured to do so, otherwise the init fails. The fix is to allow a fallback with exclude on the mirror, but not without it.

3. Private registry auth. A private registry is configured but Terraform cannot authenticate. The init errors out with “401 Unauthorized”. The fix is to set the bearer token via TF_TOKEN_<HOSTNAME> environment variable or in the CLI config.

4. Private registry with a self-signed certificate. A private registry uses a certificate not in the system trust store. The fix is to add the CA bundle to SSL_CERT_FILE or to the system trust store; do not disable verification.

5. Filesystem mirror out of date. The mirror contains version 5.0 but required_providers asks for 5.80. The fix is to update the mirror — running terraform init will not fix it; the binary has to be on disk.

Operational guidance

For a production estate:

  • Pick a source policy and write it down. Which namespaces are approved? Which mirror handles which providers? What is the fallback when the mirror is down?
  • Use a network mirror where possible. It gives you one place to audit and cache. JFrog Artifactory and Cloudsmith are common choices.
  • Sign what you publish. Internal mycorp/* providers should be GPG-signed and served from a registry that enforces the signature.
  • Test the fallback. Periodically disable the mirror and confirm init can resolve via direct. The mirror is not the only path; the team should know what the fallback does.

What comes next

The next lesson is on provider version constraints and the dependency lock — the production control for which version of a given provider runs in your estate.

Verification

Knowledge check · 6 questions

  1. Q1. What is the canonical form of a provider source address?

  2. Q2. What is the role of the `provider_installation` block in the CLI config?

  3. Q3. A network mirror can fully replace the public registry for an air-gapped environment.

  4. Q4. Which CLI configuration uses a filesystem mirror with no fallback?

  5. Q5. Which of the following are production failure modes for provider sources? (Select all that apply.)

  6. Q6. A team wants to use a third-party provider for a niche SaaS. The provider is signed and on the public registry. What is the right first step?

Passing score: 75%. Answers are checked in this browser.