Switches are created by hand in the NetBox UI, so the model and its port templates have no consumer.
terraform-netbox
YAML-driven Terraform/Terragrunt for the NetBox catalogue: the stable reference data a host is planned against. Device records are not here.
Ownership split
| Owner | Objects |
|---|---|
| this repo | sites, prefixes, DHCP pool ranges, gateways, managed IPs, VLAN groups + VLANs, device types, manufacturers, device roles, platforms, custom-field definitions, network profiles |
| autodiscovery agent | device records, interfaces, MAC addresses, switch cabling |
| UI | host names, role assignment, IP allocation (inventory -> planned) |
Writing a device from here would fight both of them, so the module declares no
netbox_device. The handful of network switches are created by hand in the
NetBox UI; this repo only defines the chassis_mac field discovery matches them
on.
Supersedes
terraform-infra, which also drove Kea DHCP. Kea is managed by the kea-operator CRs in argocd-apps (apps/base/dhcp-system/cr/).
Layout
config/<region>/<dc>/sites.yaml # site slug -> name/description
config/<region>/<dc>/subnets/net-<a>-<b>-<c>-<d>-<len>.yaml
config/<region>/<dc>/device-types/<slug>.yaml # manufacturer, model
config/<region>/<dc>/device-roles.yaml
config/<region>/<dc>/platforms.yaml # slug -> display name
config/<region>/<dc>/vlans.yaml # keyed per site
config/<region>/<dc>/network-profiles/<name>.yaml
config/<region>/<dc>/custom-fields.yaml # custom-field DEFINITIONS
config/<region>/<dc>/managed-ips.yaml
environments/<region>/<dc>/terragrunt.hcl
modules/netbox/
make plan / make apply reconcile the YAML against NetBox. State lives in
Consul under infra/terraform/netbox/<region>/<dc>/state. A site that already
exists in NetBox must be imported, not re-created: site names are unique.
Subnets (subnets/net-<a>-<b>-<c>-<d>-<len>.yaml)
The filename carries the network and mask length; the human label lives in
description.
prefix: 198.18.15.0/24
description: syd1 production
site: syd1 # NetBox site slug
router: 254 # host-octet int -> gateway IP
dhcp: # omit for a NetBox-only prefix
enabled: true
start: 200 # host-octet int
stop: 220
dns: [198.18.200.7]
domain: main.unkin.net
next_server: 198.18.19.19
Creates netbox_prefix, plus a netbox_ip_range with role dhcp and the
gateway netbox_ip_address. dns, domain and next_server are read by no
resource today; they are retained so a later change can drive Kea from this
repo without re-deriving them.
Device types (device-types/<slug>.yaml)
manufacturer: Dell
model: OptiPlex 3070
u_height: 1
VLANs (vlans.yaml)
Keyed per site. Each site gets its own site-scoped netbox_vlan_group, so the
same VID may exist in more than one site.
syd1:
vid_ranges: [[1, 4094]]
vlans:
- vid: 101
name: fabric_common_01
Network profiles (network-profiles/<name>.yaml)
A profile describes the interfaces a logical host should have. It is published
as a netbox_config_context scoped to its sites (and roles, if given), so the
UI reads profiles from the NetBox API rather than from git.
description: Dual-homed fabric host
sites: [syd1]
weight: 1000
interfaces:
- name: fabric0
vlan: 101 # VID in the site's VLAN group
subnet: net-198-18-13-0-24 # subnet key; the prefix is resolved into the context
subinterfaces: [] # optional, same shape
Custom fields (custom-fields.yaml)
Field definitions for what bootapi reads: pxe_enabled,
provision_template, domain, nameservers, gateway; plus chassis_mac,
which autodiscovery matches an LLDP neighbour on. content_types are
NetBox app_label.model strings. pxe_enabled's value is deliberately not
managed here — it is runtime state cleared by bootapi's /provisioned callback.
Providers + auth
| Provider | Source |
|---|---|
| netbox | e-breuninger/netbox 4.3.0 |
| vault | hashicorp/vault 5.6.0 |
The NetBox token is minted per run from the Vault netbox engine
(netbox/creds/terraform-netbox) and lease-revoked when the run ends; Consul
state creds come from consul_root/au/syd1/creds/terraform-netbox. Both are
granted to the terraform_netbox AppRole and the woodpecker_terraform_netbox
k8s role in terraform-vault.