nixos-config/machines/koyomi/services/hypervisor.nix

139 lines
3.5 KiB
Nix

# SPDX-FileCopyrightText: 2024 Simon Bruder <simon@sbruder.de>
#
# SPDX-License-Identifier: AGPL-3.0-or-later
{ lib, pkgs, ... }:
let
guests = {
ci-runner = {
mac = "42:80:00:00:00:02";
v4 = "10.80.32.2";
v6 = "2a01:4f9:3051:39c6:1::2";
};
hiroshi = {
mac = "42:80:00:00:00:03";
v4 = "10.80.32.3";
v6 = "2a01:4f9:3051:39c6:1::3";
};
};
# port forwarding for IPv4
portForwards = {
tcp = { };
udp = { };
};
in
{
virtualisation.libvirtd = {
enable = true;
qemu.package = pkgs.qemu_kvm;
};
boot.kernel.sysctl = {
"net.ipv4.conf.all.forwarding" = true;
"net.ipv6.conf.all.forwarding" = true;
};
systemd.network = {
enable = true;
netdevs = {
br-virt = {
netdevConfig = {
Name = "br-virt";
Kind = "bridge";
};
};
};
networks = {
br-virt = {
name = "br-virt";
address = [ "10.80.32.1/24" "2a01:4f9:3051:39c6:1::1/80" ];
};
};
};
services.resolved.enable = false;
services.dnsmasq = {
enable = true;
settings = {
interface = [ "br-virt" ];
bind-interfaces = true; # do not bind to the wildcard interface
bogus-priv = true; # do not forward revese lookups of internal addresses
dhcp-fqdn = true; # only insert qualified names of DHCP clients into DNS
domain-needed = true; # do not forward names without domain
no-hosts = true; # do not resolve hosts from /etc/hosts
no-resolv = true; # only use explicitly configured resolvers
domain = [ "koyomi.sbruder.de" ];
enable-ra = true; # required to tell clients to use DHCPv6
# Force static configuration
dhcp-range = [
"10.80.32.0,static,255.255.255.0"
"2a01:4f9:3051:39c6:1::,static,80"
];
dhcp-host = lib.flatten (lib.mapAttrsToList
(name: { mac, v4, v6 }: [
"${mac},${v4},${name}"
"${mac},[${v6}],${name}"
])
guests);
# Hetzner recursive name servers
# https://docs.hetzner.com/dns-console/dns/general/recursive-name-servers/
server = [
"185.12.64.1"
"185.12.64.2"
"2a01:4ff:ff00::add:1"
"2a01:4ff:ff00::add:2"
];
};
};
networking.firewall = {
allowedTCPPorts = map lib.toInt (lib.attrNames portForwards.tcp);
allowedUDPPorts = map lib.toInt (lib.attrNames portForwards.udp);
interfaces.br-virt = {
allowedTCPPorts = [ 53 ]; # EDNS
allowedUDPPorts = [ 53 67 547 ]; # DNS / DHCP / DHCPv6
};
};
networking.nftables = {
enable = true;
ruleset = ''
# only IPv4
table ip hypervisor-nat {
chain postrouting {
type nat hook postrouting priority filter; policy accept
oifname eth0 masquerade
}
chain prerouting {
type nat hook prerouting priority dstnat; policy accept
${lib.concatStrings (lib.mapAttrsToList (port: guest: ''
iifname eth0 tcp dport ${port} dnat to ${guests.${guest}.v4}
'') portForwards.tcp)}
${lib.concatStrings (lib.mapAttrsToList (port: guest: ''
iifname eth0 udp dport ${port} dnat to ${guests.${guest}.v4}
'') portForwards.udp)}
}
}
table inet hypervisor-filter {
chain forward {
type filter hook forward priority filter; policy drop
iifname br-virt oifname eth0 counter accept
iifname eth0 oifname br-virt counter accept
}
}
'';
};
}