netbox integration with KEA DHCP Server

netbox is an asset management system, which includes IPAM and DCIM functions. In an IT environment it serves as the source of truth. So all other services should use netbox as its backend. In this article I want to describe how to setup the integration between netbox and the KEA DHCP server.

My aim is to define everything in netbox. I define devices or virtual machines, add interfaces with MAC addresses to the new entries and finally assign IP addresses to the interfaces. This provides sufficient information to configure a DHCP server that will hand out exactly the addresses defined in netbox to the devices – once they request a new DHCP lease.

Please note that the is also an other netbox to kea integration. Please see the project on github.

KEA DHCP Server

KEA is the new and shiny DHCP service from ISC. Compared to the old DHCP server it offers many advantages. KEA, for example, provides an API that can be used to configure and control it. My instant thought was to use that API and configure the server directly with commands sent from netbox. But the module, which provides exactly this hook, is available for paid support services from ISC only.

So my second thought was to rewrite the configuration file triggered by changes in the netbox assets. Looking closer at the reservations section of a subnet definition, you will find, that is exactly represents JSON format. So it is very easy just to dump the IP address data from netbox in JSON format. Additionally the KEA configuration supports an include statement, so I can use a separate file for all my reservations of one subnet.

The example subnet configuration of my KEA DHCPv4 server looks like:

"subnet4": [
  {
    "subnet": "192.0.2.0/24",
    "interface": "eth0",
    "pools": [ { "pool": "192.0.2.128 - 192.0.2.192" } ],
    "reservations":
      <?include "/etc/kea/kea-dhcp4-reservations.json"?>
  }
],

As you can see, the file with the actual reservation data is included from a separate file.

netbox

Now for the python script, which extracts the data from netbox and writes them to a file.

First I initialize the connection to the netbox API and import all IP addresses defined. Please note that I applied a filter to get only addresses from the specific parent subnet and addresses that are assigned to an interface.

import pynetbox
import json

url   = "http://127.0.0.1:8001"
token = "0123456789abcdef"
nb    = pynetbox.api(url, token=token)

addresses = nb.ipam.ip_addresses.filter(parent='192.0.2.0/24', interface__n='null')

Now my script loops over all addresses and collects all residual information needed for the DHCP reservations:

# Initialize the list of reservations
reservations = []

# Loop over all addresses
for address in addresses:
  # Initialize the specific reservation and add the IP address.
  # Split the address, since netbox stores it in CIDR notation
  reservation = {}
  splitadd = address.address.split("/")
  reservation['ip-address'] = splitadd[0]

  # Also store additional information needed below.
  interface_url = address.interface.url
  interface_id  = address.interface.id

  # Separate between addresses of virtual servers and devices
  # to retrieve the residual information
  # Only store reservation with a MAC address entry
  if "virtualization" in interface_url:
    interface = nb.virtualization.interfaces.get(interface_id)
    if interface.mac_address:
      reservation['hostname'] = interface.virtual_machine.name
      reservation['hw-address']  = interface.mac_address
    else:
      reservation.clear()

  else:
    interface = nb.dcim.interfaces.get(interface_id)
    if interface.mac_address:
      reservation['hostname'] = interface.device.name
      reservation['hw-address']  = interface.mac_address
    else:
      reservation.clear()

  # Append the new found reservation to the list
  # if the entry exists, i.e. was not cleared.
  if reservation:
    reservations.append (reservation)

And finally the script writes the whole list to the included file in JSON format:

with open ('/etc/kea/kea-dhcp-reservations.json', 'w') as outfile:
  json.dump (reservations, outfile, indent=4)

In my test lab the file with the reservations looks like

[
    {
        "ip-address": "192.0.2.20",
        "hostname": "netbox",
        "hw-address": "52:54:00:81:92:D8"
    },
    {
        "ip-address": "192.0.2.22",
        "hostname": "server04",
        "hw-address": "80:FA:5B:74:B6:FB"
    }
]

Complete Integration

The code described above is the core of a full integration between netbox and the KEA DHCP server.

First of all, this script should be triggered from netbox every time an interface information changes. netbox provides the hook mechanism exactly for this. The hook integration is described elsewhere, so I will not go into the details here (find more at: interface onboarding).

The second part missing is the loop over all subnets the DHCP server should provide the services. This could be achieved easily with an additional loop over all subnets from netbox with an appropriate filter.

Please mail me if you have any further questions of comments to ms@sys4.de.

Michael Schwartzkopff, 04 Jan 2021

   netbox    kea    dhcp