Import Terraform Registry modules as blueprints
Platform staff can crawl the public Terraform Registry and import verified modules as platform-global blueprints — available in every organization's deploy form, with the honest limits of an opaque module.
Cloud Control's staff console can import public Terraform Registry modules and turn them into platform-global blueprints. Once imported, a module shows up in every organization's Deploy a blueprint form exactly like a built-in blueprint — no customer-side change.
This lives in the staff realm (/admin/blueprints → Terraform Registry), gated by the platform.blueprint:manage policy. Customers consume the imported blueprints; they do not run the crawler.
Two ways to import
- Browse & import — search the registry (by text, provider, verified-only), preview a module's mapped input fields, then Import as blueprint.
- Seed top verified — bulk-import the top-N verified modules by downloads (optionally filtered to one provider). Non-mappable providers are skipped and reported.
How a module becomes a blueprint
The crawler maps the registry provider to a cloud (aws→AWS, google→GCP, azurerm→AZR, alicloud→ALI — anything else is skipped), turns the module's required inputs into form fields (a module can have hundreds of inputs; only the required ones, capped at 24, are surfaced), and stores a module-block template. It reuses the existing custom-blueprints catalog, so there is no new storage and the blueprint id is custom/platform/<namespace>-<name>-<provider>.
string→ text field ·bool→ toggle ·number→ text with a numeric pattern.list/set/map/object/tuple→ a passthrough text field (paste raw HCL/JSON, e.g.["a","b"]or{"k":"v"}) — coerced when the plan is composed.- A
tagsmap becomes the standard tags field so the mandatory-tags policy is satisfiable.
Planning a registry-module blueprint
Composing the plan wraps the module in a single Terraform module block: module "<slug>" { source = "ns/name/provider" version = "…" …your inputs }, plus the platform-stamped terraform/provider/backend blocks. Your form values become the module arguments (booleans stay booleans, number-looking strings become numbers, JSON list/map strings are parsed).
A registry module is opaque at compose time — Cloud Control cannot see the resources it will create until tofu plan expands it. So the plan shows ONE placeholder resource, and the policy (no-public-bucket / mandatory-tags / region-allowlist) and cost estimate run on that placeholder. The real, per-resource policy and cost only materialize when the real runner runs tofu plan on the expanded module — exactly how the real-apply runner already works for every blueprint.
Limitations
- Apply is the mock runner unless real provisioning is enabled for the target account — same as every blueprint. "Imported" means the module is a first-class, deployable blueprint in the catalog.
- At most 24 required inputs are surfaced as fields; any overflow uses the module's own defaults (noted on the first field).
- Field coercion is app-side (numbers, booleans, JSON) — it is not full HCL type-checking; a malformed complex value passes through verbatim and is validated by
tofu. - The resource-type classification is a best-effort name heuristic (fallback
compute); it only affects which inventory bucket the placeholder lands in. - Removing an imported blueprint disables it (platform rows are never hard-deleted, so a re-import can't silently resurrect a removed one).
By default the crawler talks to the public Terraform Registry. Operators can point it at a private mirror (or the hermetic test mock) with CC_TF_REGISTRY_BASE. Requests are bounded (hard search/seed caps + per-call timeouts) and degrade to an honest error if the registry is unreachable — never a fabricated blueprint.