Why: - The netbox provider authenticated with a static netbox_token seeded by hand into KV; the vault-plugin-secrets-netbox engine mints a per-run ephemeral token that is lease-revoked when the run ends, removing the manual seed. How: - Read netbox/creds/terraform-infra via vault_generic_secret and pass the minted netbox_token to the netbox provider. - Keep kea_token from KV for now (follow-up: its own ephemeral-token engine). Depends on the netbox engine mount + netbox/creds/terraform-infra role/policy in terraform-vault being applied first.
terraform-infra
YAML-driven Terraform/Terragrunt for infrastructure state that belongs in NetBox + Kea: subnets (NetBox prefixes + Kea DHCP scopes), logical networks, and physical devices. NetBox is authoritative for all IP/interface data; this repo declares intent and lets discovery/PuppetDB fill hardware reality.
Renamed from
terraform-ipam— scope now spans devices and provisioning, not just IPAM. The old repo name is archived by the terraform-git rename.
Layout
config/<region>/<dc>/subnets/<name>.yaml # one file per subnet (prefix + DHCP scope)
config/<region>/<dc>/networks/<name>.yaml # logical networks devices join
config/<region>/<dc>/devices/<host>.yaml # one file per device (intent only)
config/<region>/<dc>/managed-ips.yaml # extra manually-managed IPs
environments/<region>/<dc>/terragrunt.hcl # one Terragrunt env per region/dc
modules/infra/ # the module
ci/puppetdb_backfill.py # reality backfill generator (local/in-cluster)
make plan / make apply reconcile the YAML against NetBox + Kea. State lives in
Consul under infra/terraform/infra/<region>/<dc>/state.
Subnet schema (subnets/<name>.yaml)
prefix: 198.18.15.0/24
description: syd1 production
site: syd1 # NetBox site slug (optional)
dhcp: # omit the block for a NetBox-only prefix
enabled: true
start: 200 # host-octet int
stop: 220
router: 254 # host-octet int -> gateway IP
dns: [198.18.200.7] # DHCP-scope DNS
next_server: 198.18.19.19
domain: main.unkin.net
Creates netbox_prefix (+ netbox_ip_range role dhcp + kea_subnet when dhcp
set, + gateway netbox_ip_address). A prefix backing a network is tagged net:<name>.
Network schema (networks/<name>.yaml)
Per-network provisioning constants — hoisted here, never repeated per device.
subnet: net-198-18-15 # which subnet's prefix backs this network
gateway: 198.18.15.254
dns: [198.18.19.16]
search: main.unkin.net
Device schema (devices/<host>.yaml) — intent only
Declare only human intent. Serial, real interface names (which vary by model —
OptiPlex 3060 = enp1s0, 3050/7080 = enp2s0), MACs and inventory are owned by the
first-boot discovery image / PuppetDB, never hardcoded here.
site: syd1
role: roles::base # puppet mgmt_class / ENC role -> NetBox device role
model_hint: optiplex-3070 # NetBox device type; discovery confirms via dmidecode
provision:
profile: almalinux9-dell_3070 # cobbler profile / kickstart template
platform: almalinux9
networks:
mgmt: 198.18.15.14/24 # requested IP; "" = next-available from the prefix
pxe: true
bootstrap_mac: a4:bb:6d:xx:xx:xx # TRANSITIONAL — see below
Mapping: netbox_device (+ netbox_manufacturer/netbox_device_type/
netbox_device_role), netbox_ip_address (static) or netbox_available_ip_address
(next-available, ignore_changes so a machine is never re-IPed). bootstrap_mac is
transitional: it seeds one placeholder netbox_device_interface + netbox_mac_address
so bootapi can key the PXE boot on MAC until the discovery image exists — remove it
once discovery/backfill populates the real NICs.
PuppetDB reality backfill
ci/puppetdb_backfill.py sweeps already-provisioned hosts and emits their hardware
reality (serial/model/UUID + every interface's MAC/IPs, incl. overlay/loopback
addresses Cobbler lacks) as reviewable YAML — the NetBox reality side, not the
intent above. PuppetDB needs no auth but is not reachable from CI; run it
in-cluster/from puppet infra. Wiring its output into NetBox is a follow-up (issue).
Providers
| Provider | Source | Notes |
|---|---|---|
| netbox | e-breuninger/netbox 4.3.0 |
OpenTofu registry |
| kea | artifactapi.k8s.syd1.au.unkin.net/terraform-unkin/kea 0.0.1 |
cluster_ref=kea |
| vault | hashicorp/vault 5.6.0 |
reads NetBox + Kea tokens |
Tokens: Vault KV v2 kv/service/terraform/infra fields netbox_token + kea_token.
Blockers
- NetBox not deployed yet (unmerged
benvin/netboxargocd branch); NetBox sites must pre-exist. KeaAPI not deployed yet (argocd-apps PR #333). Seedkv/service/terraform/infrabefore the pipeline can auth.