feat: serve local terraform repos as a provider registry #102
Reference in New Issue
Block a user
Delete Branch "benvin/terraform-provider-registry"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Why
Local terraform repos already served the Terraform network mirror protocol, but consuming that requires every user to add a
provider_installation { network_mirror }block to~/.terraformrc. Asource = "artifactapi.k8s.../ns/type"address instead triggers the provider registry protocol (service discovery at/.well-known/terraform.json+ GPG-signed SHA256SUMS), which returned 404 — hence "does not offer a provider registry."Local repos are meant to be the real thing, so this makes a terraform local repo a first-class provider registry:
terraform initinstalls from a bare source address with no client config.What
/.well-known/terraform.jsonservice discovery and theproviders.v1endpoints under/terraform/v1/providers:versions,download/{os}/{arch},sha256sums,sha256sums.sig.download_urlpoints back at the existing/api/v1/local/...path.SHA256SUMSper version and sign it with a GPG key loaded fromTF_SIGNING_KEY_PATH(optionalTF_SIGNING_KEY_PASSPHRASE); advertise the public key + key id in the download response. No key → registry stays disabled (endpoints 404), so behaviour is unchanged until the signing secret is present.internal/tfsign(key load + detached signing, viax/crypto/openpgp) andinternal/api/terraform(registry handler). ExportParseProviderZipfor reuse.TF_PROVIDER_PROTOCOLS(default5.0,6.0) sets the advertised plugin protocols.Consumer
Tests
internal/tfsign: sign + verify round-trip, disabled/missing-key paths.internal/api/terraform: dockerised full flow (discovery → versions → download → sha256sums → sig), verifying the signature against the advertised public key.Follow-ups (separate PRs)
TF_SIGNING_KEY_PATH. The/HTTPRoute already routes/.well-knownand/terraformto the API, so no gateway change is needed.Note
Anchored the
terraform/gitignore to the repo root (/terraform/) so it stops matchinginternal/*/terraform/. This surfacedinternal/provider/terraform/terraform_extra_test.go, which had been silently untracked — now committed.Local terraform repos already spoke the network mirror protocol, which needs per-consumer .terraformrc config. This adds the provider registry protocol so `terraform init` installs from a bare source address (artifactapi.k8s.../{repo}/{type}) with no client setup. - serve /.well-known/terraform.json service discovery and the providers.v1 versions/download endpoints under /terraform/v1/providers - map the Terraform namespace to the artifactapi repo name and locate the provider by type; download_url points back at the existing local file path - generate SHA256SUMS per version and sign it with a GPG key loaded from TF_SIGNING_KEY_PATH; advertise the public key + key id in the download response. No key configured -> registry stays disabled (endpoints 404) - new internal/tfsign (key loading + detached signing) and internal/api/terraform (registry handler); export ParseProviderZip for reuse - add TF_SIGNING_KEY_PATH/PASSPHRASE and TF_PROVIDER_PROTOCOLS config - unit test signing + verification; dockerised test of the full flow incl. signature verification against the advertised key Also anchor the terraform/ gitignore to the repo root so it stops swallowing internal/api/terraform and internal/provider/terraform test files (the latter had gone silently untracked).Updated (
97cdb9c): the signing key now self-provisions. On first start artifactapi generates a GPG keypair and stores it in a newsigning_keystable (INSERT ON CONFLICT DO NOTHING, so replicas converge on one key). No operator setup, no K8s secret.TF_SIGNING_KEY_PATHstays as an optional bring-your-own override.Consequences: