IPAM as code
Most teams manage DNS as code now. IP address space is usually still a spreadsheet, a wiki page, or a NetBox instance someone updates by hand. That gap is where the drift lives.
Think about how a subnet gets allocated on most teams. Someone opens the spreadsheet, scrolls for a free range, types it in, and pastes it into a Terraform variable. The spreadsheet is now the source of truth for what your VPCs actually use, except it is edited by hand, has no review, and is wrong the moment two people allocate at once. Your servers are code, your DNS is code, and the addresses underneath both are a tab in a shared document.
IP address management belongs in the same place as everything else it touches: version control, behind a plan and an apply. dnswiz has an IPAM module that is a first-class part of the Terraform provider, not a bolt-on.
Address space as resources
Blocks are your planning layer, and they organize themselves by CIDR containment. Declare the supernet and the prefixes under it, and dnswiz nests them for you. There is no parent pointer to wire up by hand.
resource "dnswiz_ipam_block" "corp" {
cidr = "10.0.0.0/8"
name = "corp"
origin = "rfc1918"
}
resource "dnswiz_ipam_block" "east" {
cidr = "10.1.0.0/16"
name = "us-east"
# placed under corp automatically, by containment
}
resource "dnswiz_ipam_network" "db" {
cidr = "10.1.5.0/24"
parent_block_id = dnswiz_ipam_block.east.id
name = "db-tier"
gateway_ip = "10.1.5.1"
}
Stop typing the next free range
The spreadsheet scroll is the part worth deleting. Instead of picking a CIDR, ask for one. Give a prefix length and get the lowest free range of that size, either from a specific block or from any block carrying a tag.
# Next free /24 inside a specific block.
resource "dnswiz_ipam_network" "app" {
parent_block_id = dnswiz_ipam_block.east.id
prefix_length = 24
name = "app-tier"
}
# Next free /24 from ANY block tagged region:eu-central-1 (a prefix pool).
# Lowest-CIDR block with room wins, so it fills predictably.
resource "dnswiz_ipam_network" "eu" {
parent_tags = ["region:eu-central-1"]
prefix_length = 24
name = "eu-app"
tags = ["env:prod", "team:platform"]
}
Allocation is locked per block on the server, so two concurrent applies never hand out the same range. If you want to look before you allocate, the same logic is a data source:
data "dnswiz_ipam_available_subnet" "next" {
block_id = dnswiz_ipam_block.east.id
prefix_length = 24
}
output "next_free_subnet" {
value = data.dnswiz_ipam_available_subnet.next.cidr
}
Hosts, and the DNS that follows them
Individual addresses are resources too. Pin one, or take the next free host in a network, and give it a hostname:
resource "dnswiz_ipam_ip_address" "vip" {
network_id = dnswiz_ipam_network.app.id
hostname = "vip"
# no address given, so the next free host is allocated on create
}
Here is the part a standalone IPAM cannot do. Point a network at one of your DNS zones (a one-time link in the console or over the API), and every address in it that has a hostname publishes its own A or AAAA record into that zone. Declare vip at the next free host in a network linked to corp.example.com, and vip.corp.example.com resolves. Because the IPAM and the DNS share one account, the address and the record are never two systems you have to keep in sync by hand.
Why hosted, and why not an add-on
NetBox is the usual answer here, and it is a good tool, but it is yours to host, patch, and back up, and it has no idea your DNS exists. A DNS provider, meanwhile, has no idea your IP plan exists. dnswiz runs both in one place, so the integration is native rather than a script you maintain between two products.
And it is not gated behind an automation tier. The whole provider, DNS, GSLB, TLS, and IPAM, is on every plan, so managing your address space in a pull request is not something you pay extra to unlock. The console is for looking at the map; the code is the source of truth.
See also: DNS and IPAM as code, the IPAM docs, DNS as code.