hashicorp/terraform
Provider installer (getproviders)
Active contributors: Martin Atkins, James Bardin.
Purpose
internal/getproviders/ (with friends internal/depsfile/ and internal/providercache/) implements provider discovery, version resolution, package download, signature verification, and dependency-lock-file maintenance. It is what runs when a user types terraform init and Terraform contacts the Terraform Registry to fetch hashicorp/aws v5.x.
The package is dense — a single file (registry_client.go, 16 KB) talks to the registry; another (package_authentication.go, 22 KB) verifies signatures; another (hash.go, 14 KB) computes and parses the multi-format hashes recorded in lock files.
Directory layout
internal/getproviders/
├── source.go # Source interface (the abstraction)
├── multi_source.go # composes multiple Sources with selectors
├── memoize_source.go # caches Source results
├── filesystem_mirror_source.go # local filesystem mirror
├── http_mirror_source.go # HTTP/HTTPS mirror
├── registry_source.go # the Terraform Registry API
├── registry_client.go # the actual HTTP client for the registry
├── mock_source.go # for tests
├── hanging_source.go # for tests; never returns
├── filesystem_search.go # locate already-installed providers in a directory
├── package_authentication.go # GPG signature verification, hash check
├── public_keys.go # bundled HashiCorp signing keys
├── hash.go # h1: / zh: / 256colon: hash formats
├── types.go # Provider, Version, PackageMeta, Selections, …
├── didyoumean.go # spelling suggestions for unknown providers
├── errors.go # typed error structures
├── supplymode.go # SupplyMode enum (provider, dev, mirror, …)
├── reattach/ # TF_REATTACH_PROVIDERS parsing
├── providerreqs/ # required-providers data structures
└── testdata/ # fixtures (4 sub-directories)The complementary lock-file package:
internal/depsfile/
├── locked.go # the LockFile type
├── load.go # parsing .terraform.lock.hcl
├── save.go # writing .terraform.lock.hcl
└── ...The on-disk cache:
internal/providercache/
├── cache.go # CacheDir abstraction
├── installer.go # the orchestrator: resolve, fetch, install, lock
└── package_install.goKey types
| Type | File | Description |
|---|---|---|
getproviders.Source |
source.go |
Interface: AvailableVersions(provider) ([]Version, []Version, error), PackageMeta(provider, version, target) (PackageMeta, error). |
getproviders.MultiSource |
multi_source.go |
Wraps several sources with hostname/namespace selectors. The default constructed in provider_source.go (root package). |
getproviders.RegistrySource |
registry_source.go |
Talks to the Terraform Registry API. |
getproviders.PackageMeta |
types.go |
Where to fetch one provider package, plus its hashes and signing keys. |
getproviders.Hash |
hash.go |
A typed hash value: h1:, zh:, 256colon:. |
getproviders.PackageAuthentication |
package_authentication.go |
Verifies a downloaded package against hashes and GPG signatures. |
depsfile.Locks |
internal/depsfile/locked.go |
The lock file content: per-provider selected version + hashes. |
providercache.Installer |
internal/providercache/installer.go |
The orchestrator that ties resolution, download, verification, and lock-file maintenance together. |
How it works
sequenceDiagram
autonumber
participant Init as command.InitCommand
participant Inst as providercache.Installer
participant Sel as Selector / version solver
participant Source as getproviders.Source
participant Cache as .terraform/providers
participant Lock as .terraform.lock.hcl
participant Sig as PackageAuthentication
Init->>Inst: EnsureProviderVersions(reqs)
Inst->>Sel: Pick versions satisfying req constraints
Sel-->>Inst: selected map[Provider]Version
Inst->>Source: PackageMeta for each
Source-->>Inst: PackageMeta (URL + hashes + signing keys)
Inst->>Cache: download archive
Inst->>Sig: verify hashes + signature
Sig-->>Inst: matched key (or error)
Inst->>Cache: extract package
Inst->>Lock: update version + hashesSources and selectors
MultiSource lets a CLI configuration redirect specific provider hostnames or namespaces to different sources:
- The default routes registered in
provider_source.go(root package) point atregistry.terraform.iofor everything. - Users can add a
provider_installation { network_mirror { url = "..." } }to~/.terraformrcto swap in an HTTP mirror. filesystem_mirror { path = "..." }points at a directory on disk.dev_overrides { hashicorp/aws = "/path/to/local/aws" }short-circuits version resolution entirely for a specific provider.
The selector logic in multi_source.go matches each requirement against the most specific selector and asks that source.
The version solver
Version resolution is straightforward — Terraform's strategy is "newest version satisfying every constraint." There's no complex backtracking solver because providers are top-level dependencies (not transitive). The function getproviders.NewestAvailableVersion (in types.go) plus filtering by VersionConstraints is most of it.
required_providers constraints are gathered from the configuration via internal/configs.Module.GatherProviderRequirements(). The result is a providerreqs.Requirements map keyed by addrs.Provider.
Authentication
package_authentication.go covers two kinds of verification:
- Hash check. Every package has one or more hashes recorded by the source (the registry returns
h1:style hashes; mirrors can supply additional formats). The downloaded archive must match one of them. Hash formats are defined inhash.go:h1:— base64 of SHA256 of the package contents.zh:— "zip hash" — SHA256 of the zipped archive.256colon:— colon-separated hex SHA256 of individual files (used in mirrors).
- GPG signature. The registry's
PackageMetaincludes a list ofSigningKeys. The downloadedSHA256SUMS.sigis verified against one of them.public_keys.gobundles HashiCorp's signing key for the trusted-by-default case; community providers can supply their own keys via the registry response.
AuthenticationResult records which key matched; this gets persisted into the lock file so future runs know the provenance.
The lock file
.terraform.lock.hcl records, per provider, the version selected and a set of hashes. The format:
provider "registry.terraform.io/hashicorp/aws" {
version = "5.42.0"
constraints = "~> 5.0"
hashes = [
"h1:abc...",
"zh:def...",
...
]
}internal/depsfile/load.go parses it; save.go writes it. The installer reconciles the lock file with what init wants to do: if the lock has a version, the installer prefers that; if there's a mismatch (because constraints changed or -upgrade was used), it resolves and then updates the lock.
The terraform providers lock subcommand (internal/command/providers_lock.go) is the user's tool for adding additional platform hashes to the lock file (e.g. so the lock works on Linux, macOS, and Windows simultaneously).
Provider cache
.terraform/providers/<host>/<namespace>/<name>/<version>/<platform>/ is where extracted provider binaries live within a working directory. internal/providercache/ manages this hierarchy. Users can configure a global cache via plugin_cache_dir in ~/.terraformrc; the installer hardlinks (or copies, on filesystems that don't support links) packages from the global cache into the local one.
Filesystem search and reattach
filesystem_search.go is used by dev_overrides and the internal-plugin mode. internal/getproviders/reattach/ parses the TF_REATTACH_PROVIDERS environment variable used during provider development; see debugging.
Integration points
- CLI:
terraform init(internal/command/init.go) instantiates aprovidercache.Installerand callsEnsureProviderVersions. Subsequent commands use the cached binaries viainternal/plugin/discovery/. - Plugin host:
internal/plugin/andinternal/plugin6/accept the binaries that this package fetched and start them as gRPC subprocesses. - Engine: the engine receives
providers.Factorys pre-built by the CLI; it doesn't talk togetprovidersdirectly.
Entry points for modification
- Adding a new source kind (e.g. an OCI registry): implement
Source, register it in theMultiSourceconfigured byprovider_source.go. - Changing how packages are authenticated:
package_authentication.go. Be conservative — this is a security-sensitive boundary. - Adding a new hash format: extend the
Hashtype inhash.goand update both production code and lock-file readers. - Adjusting how
terraform providers lockworks:internal/command/providers_lock.go.
For the protocol Terraform speaks to providers after this package fetches them, see plugin-protocol.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.