Manage Alta Labs routers (Route10 and family) with Terraform, through the Alta cloud, so the portal always shows what Terraform applied.
Status: pre-1.0. The resources below are implemented and tested against recorded fixtures, and changes have been applied to a live Route10 through the gated transaction. The schema is still moving: expect breaking changes between minor versions until 1.0.
Unofficial. This project is not affiliated with, endorsed by, or supported by Alta Labs. Alta publishes no API description, so this provider is built on an interface that was observed rather than documented, and Alta may change it without notice. What was observed, and how, is recorded in
api/schema.jsonand re-checked by the test suite rather than trusted.
Design: docs/DESIGN.md. In short:
- Port forwards, firewall rules, VLANs, routes, switch ports and DHCP reservations are written to the Alta cloud, which compiles and pushes the router's configuration.
- Every apply is one gated, commit-confirmed transaction: the router's cloud agent is paused while changes are staged, a single push is released, and the router rolls itself back unless health probes pass and the provider confirms.
- SSH to the router is used to gate, verify and roll back, and for the few device extensions the portal has no concept of.
terraform {
required_providers {
alta = {
source = "twilightcoders/alta"
}
}
}
provider "alta" {
# Named once here rather than on every resource. Both default to $ALTA_LABS_SITE_ID
# and $ALTA_LABS_DEVICE_ID.
site_id = "…"
device_id = "…"
ssh = {
host = "192.0.2.1"
host_key_fingerprint = "SHA256:…" # ssh-keyscan <host> | ssh-keygen -lf -
}
}
# A network is described once; what follows from it is derived rather than repeated.
resource "alta_vlan" "lab" {
vlan_id = 40
name = "Lab"
router_ip = "198.18.40.1/24"
}
resource "alta_dhcp_reservation" "printer" {
mac = "02:00:00:aa:bb:cc"
ip = cidrhost(alta_vlan.lab.subnet, 40)
}
resource "alta_switch_port" "uplink" {
port = 4
tagged_vlans = [alta_vlan.lab.vlan_id]
}
# For the few behaviours the cloud has no concept of. Both touch the router only,
# never the cloud, so neither triggers a configuration push.
resource "alta_device_file" "post_cfg" {
path = "/cfg/post-cfg.sh"
content = file("post-cfg.sh")
mode = "0755"
}
resource "alta_device_hook" "example" {
name = "example"
interface = "wg0"
script = "…"
}Credentials come from ALTA_LABS_EMAIL and ALTA_LABS_PASSWORD.
| Resource | What it owns |
|---|---|
alta_vlan |
one network, and the subnet, bridge and interface name derived from it |
alta_static_route |
one route |
alta_port_forward |
one destination NAT rule |
alta_firewall_rule |
one filter rule |
alta_dhcp_reservation |
one client's fixed address |
alta_switch_port |
the VLAN membership of one physical port |
alta_router_config |
every section at once, for managing a router wholesale |
alta_device_hook, alta_device_file |
the router's own scripts and files |
alta_devices (data source) |
the hardware a site has adopted |
Each resource owns its own object and leaves the rest of its collection alone, so Terraform
and the portal can manage different things in one site. Import an existing object by its id
— terraform import alta_vlan.lab 40 — and a plan straight after should show no changes.
Full reference: docs/index.md.
Alta publishes no API schema, so api/schema.json records what was
observed: endpoints extracted from the portal bundle named in its provenance, object
shapes fitted from captured responses rather than asserted, how each collection
behaves when written, and a compile mapping from cloud fields to what the router ends up
running — including the places where Alta's own compiler silently drops a field.
It is evidence, not contract, so it is re-checked rather than trusted:
make schema # refit object shapes from the captured fixtures
make portal-endpoints # re-extract endpoints from the live portal bundle (read-only)
go test ./internal/apischema # fixtures still conform
TF_ACC=1 go test ./internal/apischema -run Live # a real site and router still agree (read-only)Drift in Alta's API then shows up as a failing test instead of a surprise at apply time.
The live checks use two observation points, because one is not enough: the cloud's own read-back cannot show whether a value it stores ever reaches a router. So the compile mapping is checked against the configuration the router is actually running, which also reports a recorded defect that has been fixed — a prompt to drop the workaround rather than carry it forever.
| Component | Version |
|---|---|
| Alta Labs router | Route10, firmware 1.5g or later |
| Terraform | 1.14 or later |
| Go (development) | pinned in go.mod; fetched automatically by the go command |
Everything runs through make. Run make help for the full list.
make build # bin/terraform-provider-alta
make test # unit tests
make lint # golangci-lint (pinned in tools/go.mod)
make docs # regenerate docs/ with tfplugindocs
make install # install into the local Terraform plugin mirror
make dev-override # print a ~/.terraformrc dev_overrides blockReleases are built and signed by CI on a v* tag; the signing key belongs to the
organisation and covers every provider it publishes. See docs/RELEASING.md.