Scalable DHCP Infrastructure: Implementing Kea with a PostgreSQL Backend
In a modern DevOps environment, ephemeral storage is a liability. By default, the ISC Kea DHCP server stores its lease information in a local CSV file (memfile). While fast, this approach lacks high availability, centralized management, and persistent visibility. To move towards a professional infrastructure, offloading both leases and host reservations to a relational database like PostgreSQL is the standard protocol.
This guide details the technical journey of migrating Kea to PostgreSQL, ensuring data persistence and enabling external automation via a Python-based management layer.
In this article, provide Python code to manage reservations, lists hosts, and lists leases. This code will be incorporated into the DNS API.
https://devops-db.com/building-a-secure-dns-management-rest-api-with-rfc-2136/
1. Preparing the Data Tier
Before Kea can talk to the database, we must establish a secure environment. Unlike SQLite or flat files, PostgreSQL provides granular access control.
Database Initialization
On your PostgreSQL instance, execute the following commands. Note that we must explicitly address the public schema permissions, as modern PostgreSQL versions (15+) have tightened default security.
-- Create a dedicated service user for Kea
CREATE USER kea WITH PASSWORD 'XenCusx6jZMGBQsYmPt7l4lbnIfk6nkQ';
-- Create the specialized database
CREATE DATABASE kea_db;
GRANT ALL PRIVILEGES ON DATABASE kea_db TO kea;
-- Connect to the new database to configure schema-level permissions
\c kea_db
GRANT ALL ON SCHEMA public TO kea;
ALTER SCHEMA public OWNER TO kea;
The “Why”: Kea requires the ability to create, alter, and index tables during its initialization phase. By making the kea user the owner of the public schema within kea_db, we ensure the kea-admin tool has sufficient privileges to build the DHCP schema without granting global superuser rights.
2. Bridging the App and Database
On the Kea server, we need the administrative tools to deploy the schema.
sudo apt-get update
sudo apt-get install -y kea-admin postgresql-client
Initializing the Schema
The kea-admin tool is a wrapper that executes distribution-specific SQL scripts. It handles versioning and ensures the database is ready for DHCPv4, DHCPv6, and host management.
sudo kea-admin db-init pgsql \
-h postgresql.devops-db.internal \
-u kea \
-p XenCusx6jZMGBQsYmPt7l4lbnIfk6nkQ \
-n kea_db
3. Configuring Kea for Persistence
With the database ready, we modify /etc/kea/kea-dhcp4.conf. We are moving away from the memfile type to the postgresql backend for two critical components:
- Lease Database: Where real-time IP assignments are stored.
- Hosts Database: Where static IP reservations are stored.
{
"Dhcp4": {
"lease-database": {
"type": "postgresql",
"host": "postgresql.devops-db.internal",
"port": 5432,
"name": "kea_db",
"user": "kea",
"password": "XenCusx6jZMGBQsYmPt7l4lbnIfk6nkQ"
},
"hosts-database": {
"type": "postgresql",
"host": "postgresql.devops-db.internal",
"port": 5432,
"name": "kea_db",
"user": "kea",
"password": "XenCusx6jZMGBQsYmPt7l4lbnIfk6nkQ"
},
"hooks-libraries": [
{
"library": "/usr/lib/kea/hooks/libdhcp_host_cmds.so"
}
]
}
}
Technical Insight: By using the same database for both leases and hosts, we centralize our networking “Source of Truth”. The inclusion of libdhcp_host_cmds.so is vital for environments where host reservations need to be updated dynamically via API without restarting the Kea service.
4. Validation and Deployment
Always validate the JSON syntax before restarting the daemon. Kea is sensitive to trailing commas and incorrect paths.
# Test the configuration
sudo kea-dhcp4 -t /etc/kea/kea-dhcp4.conf
# Apply changes
sudo systemctl restart kea-dhcp4-server
sudo systemctl status kea-dhcp4-server
5. Management via Automation (Python Layer)
Editing JSON files for every new server is not scalable. Since our backend is now PostgreSQL, we can use a Python manager (kea_db_manager.py) to handle reservations. This script interfaces directly with the database, allowing for rapid provisioning of infrastructure components like Jenkins or Redis.
https://github.com/faustobranco/devops-db/tree/master/knowledge-base/python/kea
Adding Reservations
python3 kea_db_manager.py add --mac "08:00:27:f2:5c:e2" --ip "172.21.5.154" --name "srv-infrastructure-jenkins-master-01"
python3 kea_db_manager.py add --mac "08:00:27:dc:f2:71" --ip "172.21.5.165" --name "srv-infrastructure-redis-master-01"
Auditing the Environment
To verify the state of the network, we can query the reservations (intended state) and the leases (actual state):
python3 kea_db_manager.py list-reservations
python3 kea_db_manager.py list-leases
6. Deep Dive: Database Schema Analysis
Understanding how Kea stores data is crucial for troubleshooting and custom reporting.
The hosts Table (Static)
Kea stores IPv4 addresses as bigint for performance. The dhcp_identifier (MAC) is stored as bytea.
Select * from hosts;
+---------+-----------------+----------------------+-----------------+-----------------+--------------+--------------------------------------+----------------------+----------------------+-------------------+-----------------------+----------------------+--------------+----------+
| host_id | dhcp_identifier | dhcp_identifier_type | dhcp4_subnet_id | dhcp6_subnet_id | ipv4_address | hostname | dhcp4_client_classes | dhcp6_client_classes | dhcp4_next_server | dhcp4_server_hostname | dhcp4_boot_file_name | user_context | auth_key |
|---------+-----------------+----------------------+-----------------+-----------------+--------------+--------------------------------------+----------------------+----------------------+-------------------+-----------------------+----------------------+--------------+----------|
| 1 | \x080027f25ce2 | 0 | 1 | <null> | 2887058842 | srv-infrastructure-jenkins-master-01 | <null> | <null> | <null> | <null> | <null> | <null> | <null> |
| 2 | \x080027dcf271 | 0 | 1 | <null> | 2887058853 | srv-infrastructure-redis-master-01 | <null> | <null> | <null> | <null> | <null> | <null> | <null> |
+---------+-----------------+----------------------+-----------------+-----------------+--------------+--------------------------------------+----------------------+----------------------+-------------------+-----------------------+----------------------+--------------+----------+
The lease4 Table (Dynamic)
To see current active leases in a human-readable format, we use bitwise shifts to convert the bigint address back into dotted-decimal notation.
SELECT
((address >> 24) & 255) || '.' ||
((address >> 16) & 255) || '.' ||
((address >> 8) & 255) || '.' ||
(address & 255) AS ip_address,
upper(encode(hwaddr, 'hex')) AS mac_address,
valid_lifetime,
expire,
subnet_id,
fqdn_fwd,
fqdn_rev,
hostname,
state
FROM lease4;
+--------------+--------------+----------------+------------------------+-----------+----------+----------+---------------------------------------------------------+-------+
| ip_address | mac_address | valid_lifetime | expire | subnet_id | fqdn_fwd | fqdn_rev | hostname | state |
|--------------+--------------+----------------+------------------------+-----------+----------+----------+---------------------------------------------------------+-------|
| 172.21.5.103 | 080027932F14 | 3600 | 2026-04-08 08:46:15+00 | 1 | True | True | srv-infrastructure-postgresql-master-01.devops-db.local | 0 |
| 172.21.5.165 | 080027DCF271 | 3600 | 2026-04-08 08:47:53+00 | 1 | True | True | srv-infrastructure-redis-master-01.devops-db.local | 0 |
| 172.21.5.154 | 080027F25CE2 | 3600 | 2026-04-08 08:49:23+00 | 1 | True | True | srv-infrastructure-jenkins-master-01.devops-db.local | 0 |
| 172.21.5.101 | 080027251076 | 3600 | 2026-04-08 08:50:14+00 | 1 | True | True | srv-infrastructure-gitlab-master-01.devops-db.local | 0 |
| 172.21.5.100 | 00143D20055B | 3600 | 2026-04-08 08:50:36+00 | 1 | True | True | ptaj3vq0kt4x3.devops-db.local | 0 |
| 172.21.5.102 | 080027B08456 | 3600 | 2026-04-08 08:52:29+00 | 1 | True | True | srv-infrastructure-ldap-master-01.devops-db.local | 0 |
+--------------+--------------+----------------+------------------------+-----------+----------+----------+---------------------------------------------------------+-------+ Conclusion
By migrating Kea to PostgreSQL, we have transformed a simple network service into a data-driven infrastructure component. We now possess a persistent, queryable, and automatable system that can scale alongside our DevOps pipeline, providing a solid foundation for service discovery and IP address management (IPAM).
