Compare commits

...

2 Commits

Author SHA1 Message Date
unkin-agent 1ed268acda Add dnsmasq module (#537)
The router runs dnsmasq as a DNS forwarder and DHCP relay from hand-edited config, so its state is not reproducible from code.

- add `dnsmasq` module installing the package, rendering `/etc/dnsmasq.conf` from class params and running the service
- cover listen addresses/interfaces, bind mode, upstream servers, no-resolv, cache-size, domain-needed, bogus-priv, per-domain forwards and dhcp-relay
- add raw `options` lines for anything else
- add `purge_config_dir` (default off) to remove unmanaged `/etc/dnsmasq.d` files

Reviewed-on: #537
Co-authored-by: unkin-agent <unkin-agent@unkin.net>
Co-committed-by: unkin-agent <unkin-agent@unkin.net>
2026-10-03 22:40:46 +10:00
unkin-agent 47e3bdc8f5 Add router role for prodnxsr0020 (#536)
prodnxsr0020 runs FRR/OSPF hand-configured; bring its routing config under puppet without touching interfaces, firewall or dnsmasq.

- add roles::infra::network::router (base + frrouting + frr_exporter)
- enable ip_forward and disable rp_filter via sysctl::base
- add prodnxsr0020 OSPF config (dum0, dum1, bond0.201; src 198.18.21.160)
- pin dns, consul and router-id to dum0 instead of the WAN-facing primary IP
- listen sshd on 127.0.0.1 and dum0 only, knocking out the common WAN primary IP
- keep resolv.conf on the local dnsmasq (127.0.0.1)

Reviewed-on: #536
Co-authored-by: unkin-agent <unkin-agent@unkin.net>
Co-committed-by: unkin-agent <unkin-agent@unkin.net>
2026-10-03 22:40:01 +10:00
5 changed files with 174 additions and 0 deletions
@@ -0,0 +1,45 @@
---
# primary interface is the WAN uplink; pin host identity to the dum0 loopback
networking_loopback0_ip: 198.18.2.160
networking_loopback1_ip: 198.18.21.160
# dns: keep the local dnsmasq resolver
profiles::dns::base::nameservers:
- 127.0.0.1
profiles::dns::base::search:
- main.unkin.net
profiles::dns::base::primary_interface: dum0
profiles::dns::updater::deny_ranges:
- 198.18.199.0/24
- 198.18.200.0/24
- 10.42.0.0/16
- 10.43.0.0/16
- 10.10.12.0/24 # wg0
- 103.216.190.0/23 # wan uplink
profiles::consul::client::host_addr: "%{hiera('networking_loopback0_ip')}"
# ssh: listen on localhost and dum0 only; knock out the common wan primary ip
lookup_options:
ssh::server::options:
merge:
strategy: deep
knockout_prefix: '--'
ssh::server::options:
ListenAddress:
- "--%{facts.networking.ip}"
- 127.0.0.1
- "%{hiera('networking_loopback0_ip')}"
profiles::ssh::sign::principals:
- "%{hiera('networking_loopback0_ip')}"
# frrouting
frrouting::ospfd_router_id: "%{hiera('networking_loopback0_ip')}"
frrouting::ospfd_interfaces:
dum0:
area: 0.0.0.0
dum1:
area: 0.0.0.0
bond0.201:
area: 0.0.0.0
frrouting::ospf_preferred_source_enable: true
frrouting::ospf_preferred_source: "%{hiera('networking_loopback1_ip')}"
+26
View File
@@ -0,0 +1,26 @@
---
hiera_include:
- frrouting
- exporters::frr_exporter
# routing
sysctl::base::values:
net.ipv4.ip_forward:
value: '1'
net.ipv4.conf.all.rp_filter:
value: '0'
net.ipv4.conf.default.rp_filter:
value: '0'
# frrouting
exporters::frr_exporter::enable: true
frrouting::ospfd_redistribute:
- connected
frrouting::daemons:
ospfd: true
# consul
profiles::consul::client::node_rules:
- resource: service
segment: frr_exporter
disposition: write
+51
View File
@@ -0,0 +1,51 @@
# manage dnsmasq as a dns forwarder and dhcp relay
class dnsmasq (
Boolean $manage_package = true,
Boolean $manage_service = true,
String $package_name = 'dnsmasq',
String $service_name = 'dnsmasq',
Stdlib::Absolutepath $config_file = '/etc/dnsmasq.conf',
Stdlib::Absolutepath $config_dir = '/etc/dnsmasq.d',
Boolean $purge_config_dir = false,
Array[String] $interfaces = [],
Array[Stdlib::IP::Address] $listen_addresses = ['127.0.0.1'],
Enum['bind-interfaces', 'bind-dynamic', 'none'] $bind_mode = 'bind-interfaces',
Boolean $no_resolv = false,
Array[String] $servers = [],
Hash[String, Array[String]] $forwards = {},
Optional[Integer[0]] $cache_size = undef,
Boolean $domain_needed = true,
Boolean $bogus_priv = true,
Array[String] $dhcp_relays = [],
Array[String] $options = [],
) {
if $manage_package {
package { $package_name:
ensure => installed,
before => File[$config_file, $config_dir],
}
}
file { $config_dir:
ensure => directory,
recurse => $purge_config_dir,
purge => $purge_config_dir,
}
file { $config_file:
ensure => file,
owner => 'root',
group => 'root',
mode => '0644',
content => template('dnsmasq/dnsmasq.conf.erb'),
}
if $manage_service {
service { $service_name:
ensure => running,
enable => true,
subscribe => File[$config_file, $config_dir],
}
}
}
@@ -0,0 +1,40 @@
# THIS FILE IS MANAGED BY PUPPET
user=dnsmasq
group=dnsmasq
conf-dir=<%= @config_dir %>,.rpmnew,.rpmsave,.rpmorig
<% @interfaces.each do |iface| -%>
interface=<%= iface %>
<% end -%>
<% unless @listen_addresses.empty? -%>
listen-address=<%= @listen_addresses.join(',') %>
<% end -%>
<% unless @bind_mode == 'none' -%>
<%= @bind_mode %>
<% end -%>
<% if @no_resolv -%>
no-resolv
<% end -%>
<% if @domain_needed -%>
domain-needed
<% end -%>
<% if @bogus_priv -%>
bogus-priv
<% end -%>
<% if @cache_size -%>
cache-size=<%= @cache_size %>
<% end -%>
<% @servers.each do |server| -%>
server=<%= server %>
<% end -%>
<% @forwards.keys.sort.each do |domain| -%>
<% @forwards[domain].each do |server| -%>
server=/<%= domain %>/<%= server %>
<% end -%>
<% end -%>
<% @dhcp_relays.each do |relay| -%>
dhcp-relay=<%= relay %>
<% end -%>
<% @options.each do |line| -%>
<%= line %>
<% end -%>
@@ -0,0 +1,12 @@
# roles::infra::network::router
# an ospf router; frr only, interfaces and firewall are managed outside puppet
#
class roles::infra::network::router {
if $facts['firstrun'] {
include profiles::defaults
include profiles::firstrun::init
}else{
include profiles::defaults
include profiles::base
}
}