This module installs and configures ISC Kea DHCP server (version 3.x) from the official ISC Cloudsmith repositories. It supports:
- DHCPv4 server (
kea-dhcp4) - DHCPv6 server (
kea-dhcp6) - DHCP-DDNS server (
kea-dhcp-ddns)
The module is designed for Debian and Ubuntu systems and uses Hiera-driven configuration for maximum flexibility.
- Puppet 7.x or 8.x
puppetlabs-stdlibmodulepuppetlabs-aptmodule
Include the module and enable the components you need via Hiera:
include kea# In your Hiera data
kea::dhcp4:
enable: true
interfaces:
- 'eth0'kea::dhcp4:
enable: true
interfaces:
- 'eth0'
valid_lifetime: 4000
renew_timer: 1000
rebind_timer: 2000
subnets:
- id: 1
subnet: '192.168.1.0/24'
pools:
- pool: '192.168.1.100 - 192.168.1.200'
option-data:
- name: 'routers'
data: '192.168.1.1'
- name: 'domain-name-servers'
data: '8.8.8.8, 8.8.4.4'
- name: 'domain-name'
data: 'example.com'kea::dhcp4:
enable: true
interfaces:
- 'eth0'
subnets:
- id: 1
subnet: '192.168.1.0/24'
pools:
- pool: '192.168.1.100 - 192.168.1.200'
reservations:
- hw-address: '00:11:22:33:44:55'
ip-address: '192.168.1.10'
hostname: 'server1'
- hw-address: '00:11:22:33:44:56'
ip-address: '192.168.1.11'
hostname: 'server2'kea::mysql_backend: true
kea::dhcp4:
enable: true
interfaces:
- 'eth0'
lease_database:
type: 'mysql'
name: 'kea'
host: 'localhost'
port: 3306
user: 'kea'
password: 'secret'
subnets:
- id: 1
subnet: '192.168.1.0/24'
pools:
- pool: '192.168.1.100 - 192.168.1.200'kea::dhcp6:
enable: true
interfaces:
- 'eth0'
preferred_lifetime: 3000
valid_lifetime: 4000
subnets:
- id: 1
subnet: '2001:db8:1::/64'
pools:
- pool: '2001:db8:1::100 - 2001:db8:1::200'
option-data:
- name: 'dns-servers'
data: '2001:db8:1::1'kea::ddns:
enable: true
ip_address: '127.0.0.1'
port: 53001
forward_ddns:
ddns_domains:
- name: 'example.com.'
dns_servers:
- ip_address: '192.168.1.1'
port: 53
kea::dhcp4:
enable: true
interfaces:
- 'eth0'
ddns_send_updates: true
ddns_qualifying_suffix: 'example.com'
ddns_replace_client_name: 'when-not-present'
subnets:
- id: 1
subnet: '192.168.1.0/24'
pools:
- pool: '192.168.1.100 - 192.168.1.200'kea::hooks_package: true
kea::dhcp4:
enable: true
interfaces:
- 'eth0'
hooks_libraries:
- library: '/usr/lib/x86_64-linux-gnu/kea/hooks/libdhcp_lease_cmds.so'
- library: '/usr/lib/x86_64-linux-gnu/kea/hooks/libdhcp_stat_cmds.so'
subnets:
- id: 1
subnet: '192.168.1.0/24'
pools:
- pool: '192.168.1.100 - 192.168.1.200'Kea supports high availability configurations with automatic failover. This module provides structured HA support with validated parameters. The module automatically configures the HA hook library and merges it with any manually specified hooks.
HA Modes:
hot-standby: Active/passive failover. One primary handles all traffic; standby takes over on failure.load-balancing: Active/active. Both servers handle traffic, with automatic failover.passive-backup: Simple backup without state synchronization (Kea 2.4+).
# On server1.example.com (primary)
kea::dhcp4:
enable: true
interfaces:
- 'eth0'
ha:
mode: 'hot-standby'
this_server: 'server1' # Optional: auto-detected from $facts['networking']['fqdn']
heartbeat_delay: 10000
max_response_delay: 60000
max_unacked_clients: 5
peers:
- name: 'server1'
url: 'http://192.168.1.10:8000/'
role: 'primary'
- name: 'server2'
url: 'http://192.168.1.11:8000/'
role: 'standby'
subnets:
- id: 1
subnet: '192.168.1.0/24'
pools:
- pool: '192.168.1.100 - 192.168.1.200'# On server2.example.com (standby)
kea::dhcp4:
enable: true
interfaces:
- 'eth0'
ha:
mode: 'hot-standby'
this_server: 'server2'
heartbeat_delay: 10000
max_response_delay: 60000
max_unacked_clients: 5
peers:
- name: 'server1'
url: 'http://192.168.1.10:8000/'
role: 'primary'
- name: 'server2'
url: 'http://192.168.1.11:8000/'
role: 'standby'
subnets:
- id: 1
subnet: '192.168.1.0/24'
pools:
- pool: '192.168.1.100 - 192.168.1.200'In load-balancing mode, both servers actively serve DHCP requests. The servers coordinate lease assignments to prevent conflicts.
kea::dhcp4:
enable: true
interfaces:
- 'eth0'
ha:
mode: 'load-balancing'
heartbeat_delay: 10000
max_response_delay: 60000
max_unacked_clients: 5
peers:
- name: 'server1'
url: 'http://192.168.1.10:8000/'
role: 'primary'
- name: 'server2'
url: 'http://192.168.1.11:8000/'
role: 'secondary'
subnets:
- id: 1
subnet: '192.168.1.0/24'
pools:
- pool: '192.168.1.100 - 192.168.1.200'Note: In load-balancing mode, use primary and secondary roles (not standby).
| Parameter | Type | Default | Description |
|---|---|---|---|
mode |
String | - | HA mode: hot-standby, load-balancing, passive-backup |
this_server |
String | auto | Name of this server (must match a peer name) |
peers |
Array | - | Array of peer configurations |
heartbeat_delay |
Integer | 10000 | Heartbeat interval in milliseconds |
max_response_delay |
Integer | 60000 | Max time to wait for partner response (ms) |
max_unacked_clients |
Integer | 5 | Failed client queries before failover |
max_ack_delay |
Integer | - | Max delay for client acknowledgments (ms) |
sync_timeout |
Integer | - | Lease database sync timeout (ms) |
sync_page_limit |
Integer | - | Max leases per sync page |
delayed_updates_limit |
Integer | - | Max queued lease updates |
send_lease_updates |
Boolean | - | Enable lease update notifications |
sync_leases |
Boolean | - | Enable lease synchronization |
wait_backup_ack |
Boolean | - | Wait for backup server acknowledgment |
multi_threading |
Hash | - | Multi-threading configuration |
state_machine |
Hash | - | State machine timing configuration |
Each peer in the peers array:
| Parameter | Type | Required | Description |
|---|---|---|---|
name |
String | Yes | Unique peer name (use FQDN for auto-detection) |
url |
String | Yes | HTTP URL for HA communication |
role |
String | Yes | Peer role: primary, secondary, standby, backup |
auto_failover |
Boolean | No | Enable automatic failover for this peer (default: true) |
If this_server is not specified, the module automatically detects it by matching
$facts['networking']['fqdn'] against the peer names. This allows using the same Hiera
configuration on both HA nodes:
# In common.yaml - same config works on both servers
kea::dhcp4:
enable: true
ha:
mode: 'hot-standby'
# this_server is auto-detected from FQDN
peers:
- name: 'dhcp1.example.com'
url: 'http://192.168.1.10:8000/'
role: 'primary'
- name: 'dhcp2.example.com'
url: 'http://192.168.1.11:8000/'
role: 'standby'kea::dhcp4:
enable: true
interfaces:
- 'eth0'
client_classes:
- name: 'voip-phones'
test: "substring(option[60].hex,0,6) == 'Polycom'"
option-data:
- name: 'tftp-server-name'
data: 'tftp.example.com'
- name: 'printers'
test: "substring(option[60].hex,0,2) == 'HP'"
subnets:
- id: 1
subnet: '192.168.1.0/24'
pools:
- pool: '192.168.1.100 - 192.168.1.200'kea::dhcp4:
enable: true
interfaces:
- 'eth0'
logging:
severity: 'DEBUG'
debuglevel: 50
output: '/var/log/kea/kea-dhcp4.log'
maxsize: 20971520 # 20MB
maxver: 10
subnets:
- id: 1
subnet: '192.168.1.0/24'
pools:
- pool: '192.168.1.100 - 192.168.1.200'Instead of defining all subnets inline within kea::dhcp4::subnets, you can define them
separately in Hiera using the kea::dhcp4::subnets hash. This allows subnets to be
defined at any level of your Hiera hierarchy and merged together using deep merge.
This is particularly useful when you have many subnets and want to organize them across multiple Hiera files or hierarchy levels.
# In common.yaml - define shared subnets
kea::dhcp4::subnets:
management:
subnet: '10.0.0.0/24'
pools:
- pool: '10.0.0.100 - 10.0.0.200'
option_data:
- name: 'routers'
data: '10.0.0.1'
# In datacenter/dc1.yaml - add datacenter-specific subnets
kea::dhcp4::subnets:
dc1-servers:
subnet: '10.1.0.0/24'
pools:
- pool: '10.1.0.100 - 10.1.0.200'
option_data:
- name: 'routers'
data: '10.1.0.1'
dc1-workstations:
subnet: '10.1.1.0/24'
pools:
- pool: '10.1.1.100 - 10.1.1.200'
option_data:
- name: 'routers'
data: '10.1.1.1'
# In nodes/dhcp01.example.com.yaml - node-specific subnets
kea::dhcp4::subnets:
guest-wifi:
subnet: '172.16.0.0/24'
pools:
- pool: '172.16.0.50 - 172.16.0.250'
valid_lifetime: 1800
option_data:
- name: 'routers'
data: '172.16.0.1'With deep merge enabled in your Hiera configuration, all these subnets will be combined. The module creates:
- Individual subnet files in
/etc/kea/subnets4.d/(e.g.,management.json,dc1-servers.json) - A master include file at
/etc/kea/kea-dhcp4-subnets.jsonthat uses Kea's<?include?>directive to pull in each individual subnet file - The main config
kea-dhcp4.confincludes the master subnets file
This creates a proper include chain:
kea-dhcp4.conf → kea-dhcp4-subnets.json → subnets4.d/*.json
Subnet IDs are auto-generated from the subnet name if not explicitly provided. This uses
fqdn_rand() to create a stable, unique ID based on the subnet's Hiera key name. You can
still manually specify an id if you need a specific value.
Each subnet in the hash supports the following keys:
| Key | Type | Required | Description |
|---|---|---|---|
id |
Integer | No | Unique subnet ID (auto-generated if not provided) |
subnet |
String | Yes | CIDR notation (e.g., '192.168.1.0/24') |
pools |
Array | No | Address pool definitions |
option_data |
Array | No | DHCP options for this subnet |
reservations |
Array | No | Host reservations |
relay |
Hash | No | Relay agent configuration |
interface |
String | No | Interface for directly connected subnets |
valid_lifetime |
Integer | No | Override global valid lifetime |
renew_timer |
Integer | No | Override global T1 timer |
rebind_timer |
Integer | No | Override global T2 timer |
extra_config |
Hash | No | Additional Kea configuration options |
DHCPv6 subnets work the same way, using kea::dhcp6::subnets:
kea::dhcp6::subnets:
office-v6:
subnet: '2001:db8:1::/64'
pools:
- pool: '2001:db8:1::100 - 2001:db8:1::1ff'
option_data:
- name: 'dns-servers'
data: '2001:db8:1::1'
guest-v6:
subnet: '2001:db8:2::/64'
pools:
- pool: '2001:db8:2::100 - 2001:db8:2::fff'
# Prefix delegation for guest CPE devices
pd_pools:
- prefix: '2001:db8:8000::'
prefix_len: 48
delegated_len: 56DHCPv6 subnets support additional keys:
| Key | Type | Description |
|---|---|---|
pd_pools |
Array | Prefix delegation pool definitions |
interface_id |
String | Interface ID for relay agent subnet selection |
preferred_lifetime |
Integer | Override preferred lifetime |
rapid_commit |
Boolean | Enable rapid commit for this subnet |
Shared networks allow multiple subnets to share a common physical network segment. This is useful for scenarios like network migrations, VoIP deployments, or multi-tenant environments.
Each shared network is managed as an individual JSON file in /etc/kea/shared-networks4.d/
(or shared-networks6.d/ for DHCPv6), using Kea's <?include?> directive for clean
separation.
# DHCPv4 shared networks
kea::dhcp4::shared_networks:
office-floor1:
interface: 'eth0'
option_data:
- name: 'domain-name'
data: 'floor1.example.com'
subnets:
- subnet: '192.168.1.0/24'
pools:
- pool: '192.168.1.100 - 192.168.1.200'
option_data:
- name: 'routers'
data: '192.168.1.1'
- subnet: '192.168.2.0/24'
pools:
- pool: '192.168.2.100 - 192.168.2.200'
option_data:
- name: 'routers'
data: '192.168.2.1'
guest-network:
interface: 'eth1'
subnets:
- subnet: '10.0.0.0/24'
pools:
- pool: '10.0.0.50 - 10.0.0.250'
valid_lifetime: 1800# DHCPv6 shared networks
kea::dhcp6::shared_networks:
office-v6:
interface: 'eth0'
subnets:
- subnet: '2001:db8:1::/64'
pools:
- pool: '2001:db8:1::100 - 2001:db8:1::1ff'
- subnet: '2001:db8:2::/64'
pools:
- pool: '2001:db8:2::100 - 2001:db8:2::1ff'Each shared network supports:
| Key | Type | Description |
|---|---|---|
name |
String | Network name (defaults to Hiera key) |
interface |
String | Interface for directly connected networks |
relay |
Hash | Relay agent configuration |
option_data |
Array | DHCP options for all subnets in network |
subnets |
Array | Array of subnet definitions |
valid_lifetime |
Integer | Override valid lifetime for all subnets |
extra_config |
Hash | Additional Kea configuration options |
| Parameter | Type | Default | Description |
|---|---|---|---|
repo_version |
String | '3-0' |
Kea repository version |
manage_repo |
Boolean | true |
Whether to manage the apt repository |
dhcp4 |
Hash | undef |
DHCPv4 configuration hash |
dhcp6 |
Hash | undef |
DHCPv6 configuration hash |
ddns |
Hash | undef |
DHCP-DDNS configuration hash |
hooks_package |
Boolean | true |
Install open source hooks package |
mysql_backend |
Boolean | false |
Install MySQL backend support |
postgresql_backend |
Boolean | false |
Install PostgreSQL backend support |
config_dir |
String | '/etc/kea' |
Configuration directory |
run_dir |
String | '/run/kea' |
Runtime directory |
log_dir |
String | '/var/log/kea' |
Log directory |
lib_dir |
String | '/var/lib/kea' |
Library/state directory |
| Key | Type | Default | Description |
|---|---|---|---|
enable |
Boolean | - | Enable this component (required) |
service_ensure |
String | 'running' |
Service state |
service_enable |
Boolean | true |
Enable service at boot |
interfaces |
Array | ['*'] |
Interfaces to listen on |
valid_lifetime |
Integer | 4000 |
Lease valid lifetime (seconds) |
renew_timer |
Integer | 1000 |
T1 renew timer (seconds) |
rebind_timer |
Integer | 2000 |
T2 rebind timer (seconds) |
calculate_tee_times |
Boolean | - | Auto-calculate T1/T2 from valid_lifetime |
t1_percent |
Float | - | T1 as percentage of valid_lifetime (0.0-1.0) |
t2_percent |
Float | - | T2 as percentage of valid_lifetime (0.0-1.0) |
store_extended_info |
Boolean | - | Store extended info in leases |
allocator |
String | - | Address allocation strategy (iterative, random, flq) |
subnets |
Array | [] |
Subnet definitions |
option_data |
Array | [] |
Global DHCP options |
reservations |
Array | [] |
Global host reservations |
hooks_libraries |
Array | [] |
Hook libraries to load |
client_classes |
Array | [] |
Client class definitions |
lease_database |
Hash | memfile | Lease database config |
logging |
Hash | defaults | Logging configuration |
control_socket |
Hash | enabled | Control socket config |
sanity_checks |
Hash | - | Lease sanity checking config |
expired_leases_processing |
Hash | - | Expired lease reclamation config |
ha |
Hash | - | High availability configuration (see HA section) |
| Key | Type | Default | Description |
|---|---|---|---|
preferred_lifetime |
Integer | 3000 |
Preferred lifetime (seconds) |
pd_allocator |
String | - | Prefix delegation allocator (iterative, random, flq) |
Configure how Kea reclaims expired leases:
kea::dhcp4:
enable: true
expired_leases_processing:
reclaim_timer_wait_time: 10
flush_reclaimed_timer_wait_time: 25
hold_reclaimed_time: 3600
max_reclaim_leases: 100
max_reclaim_time: 250
unwarned_reclaim_cycles: 5| Key | Type | Default | Description |
|---|---|---|---|
reclaim_timer_wait_time |
Integer | 10 |
Seconds between reclamation cycles |
flush_reclaimed_timer_wait_time |
Integer | 25 |
Seconds between flushing reclaimed leases to DB |
hold_reclaimed_time |
Integer | 3600 |
Seconds to hold reclaimed lease in DB |
max_reclaim_leases |
Integer | 100 |
Max leases to reclaim per cycle |
max_reclaim_time |
Integer | 250 |
Max milliseconds for reclamation cycle |
unwarned_reclaim_cycles |
Integer | 5 |
Cycles without warning before logging |
Configure lease sanity checking:
kea::dhcp4:
enable: true
sanity_checks:
lease_checks: 'fix-del' # Options: none, warn, fix, fix-del, del| Key | Type | Default | Description |
|---|---|---|---|
enable |
Boolean | - | Enable DDNS (required) |
ip_address |
String | '127.0.0.1' |
Listen address |
port |
Integer | 53001 |
Listen port |
dns_server_timeout |
Integer | 500 |
DNS server timeout (ms) |
forward_ddns |
Hash | {} |
Forward DNS update config |
reverse_ddns |
Hash | {} |
Reverse DNS update config |
tsig_keys |
Array | [] |
TSIG key definitions |
- Only supports Debian and Ubuntu (Debian family)
- Does not manage the Kea Control Agent (by design)
- Database schema initialization must be done manually when using MySQL/PostgreSQL backends
# Install dependencies
bundle install
# Run all tests
bundle exec rake
# Run only spec tests
bundle exec rake spec
# Run with code coverage
COVERAGE=yes bundle exec rake spec
# Run linting
bundle exec rake lint
# Validate syntax
bundle exec rake syntax
# Check metadata.json
bundle exec rake metadata_lintContributions are welcome! Please ensure:
- All tests pass:
bundle exec rake spec - Code passes
puppet-lint:bundle exec rake lint - New features include appropriate spec tests
- Templates generate valid JSON (test with
kea-dhcp4 -t /etc/kea/kea-dhcp4.conf)
Apache-2.0