Open-Source Wikis

/

Terraform

/

Systems

/

Provider installer (`getproviders`)

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.go

Key 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 + hashes

Sources 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 at registry.terraform.io for everything.
  • Users can add a provider_installation { network_mirror { url = "..." } } to ~/.terraformrc to 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:

  1. 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 in hash.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).
  2. GPG signature. The registry's PackageMeta includes a list of SigningKeys. The downloaded SHA256SUMS.sig is verified against one of them. public_keys.go bundles 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 a providercache.Installer and calls EnsureProviderVersions. Subsequent commands use the cached binaries via internal/plugin/discovery/.
  • Plugin host: internal/plugin/ and internal/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 to getproviders directly.

Entry points for modification

  • Adding a new source kind (e.g. an OCI registry): implement Source, register it in the MultiSource configured by provider_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 Hash type in hash.go and update both production code and lock-file readers.
  • Adjusting how terraform providers lock works: 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.

Provider installer (`getproviders`) – Terraform wiki | Factory