diff --git a/nixos/lab.nix b/nixos/lab.nix index fac3ea7..373e276 100644 --- a/nixos/lab.nix +++ b/nixos/lab.nix @@ -1,14 +1,24 @@ { lab.networking = { - publicIPv4 = "192.145.57.90"; - publicRouterIPv6 = "2a0d:6e00:1a77::1"; - dockerSwarmIPv4 = "192.168.30.8"; - dockerSwarmIPv6 = "2a0d:6e00:1a77:30:c8fe:c0ff:feff:ee08"; - dmzRouterIPv4 = "192.168.30.1"; - dmzRouterIPv6 = "2a0d:6e00:1a77:30::1"; - dmzServicesIPv4 = "192.168.30.7"; - dmzServicesIPv6 = "2a0d:6e00:1a77:30::7"; - dmzIPv4PrefixLength = "24"; - dmzIPv6PrefixLength = "64"; + public = { + ipv4.router = "192.145.57.90"; + ipv6.router = "2a0d:6e00:1a77::1"; + }; + + dmz = { + ipv4 = { + prefixLength = "24"; + dockerSwarm = "192.168.30.8"; + router = "192.168.30.1"; + services = "192.168.30.7"; + }; + + ipv6 = { + prefixLength = "64"; + dockerSwarm = "2a0d:6e00:1a77:30:c8fe:c0ff:feff:ee08"; + router = "2a0d:6e00:1a77:30::1"; + services = "2a0d:6e00:1a77:30::7"; + }; + }; }; } diff --git a/nixos/machines/default.nix b/nixos/machines/default.nix index 5e4387c..9094656 100644 --- a/nixos/machines/default.nix +++ b/nixos/machines/default.nix @@ -77,13 +77,13 @@ nixosModule = { config, ... }: { lab = { - networking.dmzServices.enable = true; + networking.dmz.services.enable = true; vm = { macAddress = "BA:DB:EE:F0:00:07"; staticNetworking = true; - staticIPv4 = config.lab.networking.dmzServicesIPv4; - staticIPv6 = config.lab.networking.dmzServicesIPv6; + staticIPv4 = config.lab.networking.dmz.ipv4.services; + staticIPv6 = config.lab.networking.dmz.ipv6.services; }; }; }; diff --git a/nixos/modules/data-sharing.nix b/nixos/modules/data-sharing.nix index 744b87f..280abd5 100644 --- a/nixos/modules/data-sharing.nix +++ b/nixos/modules/data-sharing.nix @@ -19,7 +19,7 @@ let nfsExports = lib.strings.concatLines ( builtins.map (share: - "${cfg.nfsRoot}${share} 192.168.30.0/${config.lab.networking.dmzIPv4PrefixLength}(rw,sync,no_subtree_check,no_root_squash)" + "${cfg.nfsRoot}${share} 192.168.30.0/${config.lab.networking.dmz.ipv4.prefixLength}(rw,sync,no_subtree_check,no_root_squash)" ) nfsShares ); @@ -52,7 +52,7 @@ in }; config = lib.mkIf cfg.enable { - networking.firewall.interfaces.${config.lab.networking.dmzBridgeName}.allowedTCPPorts = [ + networking.firewall.interfaces.${config.lab.networking.dmz.bridgeName}.allowedTCPPorts = [ 2049 # NFS 5432 # PostgeSQL 111 # NFS diff --git a/nixos/modules/default.nix b/nixos/modules/default.nix index 623e356..fcc11ea 100644 --- a/nixos/modules/default.nix +++ b/nixos/modules/default.nix @@ -11,8 +11,10 @@ in ./backups.nix ./networking ./data-sharing.nix + ./globals.nix ]; + # TODO: remove this option; make this explicit on the host. options.lab.dataHost.enable = lib.mkOption { default = false; type = lib.types.bool; @@ -26,6 +28,6 @@ in config.lab = lib.mkIf cfg.dataHost.enable { backups.enable = true; data-sharing.enable = true; - networking.allowDMZConnectivity = true; + networking.dmz.allowConnectivity = true; }; } diff --git a/nixos/modules/globals.nix b/nixos/modules/globals.nix new file mode 100644 index 0000000..3f62be2 --- /dev/null +++ b/nixos/modules/globals.nix @@ -0,0 +1,89 @@ +{ lib, ... }: { + options.lab = { + + networking = { + public = { + ipv4 = { + router = lib.mkOption { + type = lib.types.str; + description = '' + Public IPv4 address of the router. + ''; + }; + }; + + ipv6 = { + router = lib.mkOption { + type = lib.types.str; + description = '' + Publicly routable IPv6 address of the router. + ''; + }; + }; + }; + + dmz = { + ipv4 = { + prefixLength = lib.mkOption { + type = lib.types.str; + description = '' + IPv4 prefix length of DMZ network. + ''; + }; + + dockerSwarm = lib.mkOption { + type = lib.types.str; + description = '' + IPv4 address of the Docker Swarm in the DMZ. + ''; + }; + + + router = lib.mkOption { + type = lib.types.str; + description = '' + The router's IPv4 address on the DMZ network. + ''; + }; + + services = lib.mkOption { + type = lib.types.str; + description = '' + The IPv4 address of the interface serving DHCP and DNS on the DMZ network. + ''; + }; + }; + + ipv6 = { + prefixLength = lib.mkOption { + type = lib.types.str; + description = '' + IPv6 prefix length of DMZ network. + ''; + }; + + dockerSwarm = lib.mkOption { + type = lib.types.str; + description = '' + Globally routable IPv6 address of the Docker Swarm. + ''; + }; + + router = lib.mkOption { + type = lib.types.str; + description = '' + The router's IPv6 address on the DMZ network. + ''; + }; + + services = lib.mkOption { + type = lib.types.str; + description = '' + The IPv6 address of the interface serving DHCP and DNS on the DMZ network. + ''; + }; + }; + }; + }; + }; +} diff --git a/nixos/modules/networking/default.nix b/nixos/modules/networking/default.nix index 3924953..16416f6 100644 --- a/nixos/modules/networking/default.nix +++ b/nixos/modules/networking/default.nix @@ -1,95 +1,25 @@ { lib, config, machine, ... }: let cfg = config.lab.networking; in { - imports = [ ./dmz ]; + imports = [ ./dmz_services ]; options.lab.networking = { - allowDMZConnectivity = lib.mkOption { - default = false; - type = lib.types.bool; - description = '' - Whether to allow networking on the DMZ bridge interface. - ''; - }; + dmz = { + allowConnectivity = lib.mkOption { + default = false; + type = lib.types.bool; + description = '' + Whether to allow networking on the DMZ bridge interface. + ''; + }; - staticDMZIPv4Address = lib.mkOption { - default = ""; - type = lib.types.str; - description = '' - Assign a static IPv4 address on the DMZ interface. - ''; - }; - - staticDMZIPv6Address = lib.mkOption { - default = ""; - type = lib.types.str; - description = '' - Assign a static IPv6 address on the DMZ interface. - ''; - }; - - publicIPv4 = lib.mkOption { - type = lib.types.str; - description = '' - Public IPv4 address of our home. - ''; - }; - - publicRouterIPv6 = lib.mkOption { - type = lib.types.str; - description = '' - Publicly routable IPv6 address of the router. - ''; - }; - - dockerSwarmIPv4 = lib.mkOption { - type = lib.types.str; - description = '' - Internal IPv4 address of the Docker Swarm. - ''; - }; - - dockerSwarmIPv6 = lib.mkOption { - type = lib.types.str; - description = '' - Globally routable IPv6 address of the Docker Swarm. - ''; - }; - - dmzRouterIPv4 = lib.mkOption { - type = lib.types.str; - description = '' - The router's IPv4 address on the DMZ network. - ''; - }; - - dmzRouterIPv6 = lib.mkOption { - type = lib.types.str; - description = '' - The router's IPv6 address on the DMZ network. - ''; - }; - - dmzServicesIPv4 = lib.mkOption { - type = lib.types.str; - description = '' - The IPv4 address of the interface serving DHCP and DNS on the DMZ network. - ''; - }; - - dmzServicesIPv6 = lib.mkOption { - type = lib.types.str; - description = '' - The IPv6 address of the interface serving DHCP and DNS on the DMZ network. - ''; - }; - - dmzBridgeName = lib.mkOption { - default = "bridgedmz"; - type = lib.types.str; - description = '' - The name of the DMZ bridge. - ''; + bridgeName = lib.mkOption { + default = "bridgedmz"; + type = lib.types.str; + description = '' + The name of the DMZ bridge. + ''; + }; }; mainNicNamePattern = lib.mkOption { @@ -99,30 +29,16 @@ in { Pattern to match the name of this machine's main NIC. ''; }; - - dmzIPv4PrefixLength = lib.mkOption { - type = lib.types.str; - description = '' - IPv4 prefix length of DMZ network. - ''; - }; - - dmzIPv6PrefixLength = lib.mkOption { - type = lib.types.str; - description = '' - IPv6 prefix length of DMZ network. - ''; - }; }; config = { networking = { domain = if machine.type == "physical" then "hyp" else "dmz"; - nftables.enable = false; + nftables.enable = true; useDHCP = false; firewall = { - enable = false; + enable = true; checkReversePath = false; }; }; @@ -143,7 +59,7 @@ in { "20-bridgedmz" = { netdevConfig = { Kind = "bridge"; - Name = cfg.dmzBridgeName; + Name = cfg.dmz.bridgeName; }; }; }; @@ -165,26 +81,24 @@ in { networkConfig = { IPv6AcceptRA = false; LinkLocalAddressing = "no"; - Bridge = cfg.dmzBridgeName; + Bridge = cfg.dmz.bridgeName; }; }; "40-bridgedmz" = { - matchConfig.Name = cfg.dmzBridgeName; + matchConfig.Name = cfg.dmz.bridgeName; linkConfig.RequiredForOnline = "carrier"; networkConfig = { - IPv6AcceptRA = cfg.allowDMZConnectivity; - LinkLocalAddressing = if cfg.allowDMZConnectivity then "ipv6" else "no"; - DHCP = lib.mkIf (cfg.allowDMZConnectivity && cfg.staticDMZIPv4Address == "") "yes"; - Address = lib.lists.optional (cfg.staticDMZIPv4Address != "") cfg.staticDMZIPv4Address - ++ lib.lists.optional (cfg.staticDMZIPv6Address != "") cfg.staticDMZIPv6Address; + IPv6AcceptRA = cfg.dmz.allowConnectivity; + LinkLocalAddressing = if cfg.dmz.allowConnectivity then "ipv6" else "no"; + DHCP = "yes"; }; }; "40-vms" = { matchConfig.Name = "vm-*"; - networkConfig.Bridge = cfg.dmzBridgeName; + networkConfig.Bridge = cfg.dmz.bridgeName; }; }; }; diff --git a/nixos/modules/networking/dmz/dnsmasq.nix b/nixos/modules/networking/dmz/dnsmasq.nix deleted file mode 100644 index 6140184..0000000 --- a/nixos/modules/networking/dmz/dnsmasq.nix +++ /dev/null @@ -1,50 +0,0 @@ -{ config, ... }: -let - inherit (config.lab.networking) publicIPv4 dockerSwarmIPv4 dmzServicesIPv4 dmzServicesIPv6 dmzRouterIPv4; -in -{ - no-resolv = true; - local = "/dmz/"; - dhcp-fqdn = true; - no-hosts = true; - expand-hosts = true; - domain = "dmz"; - dhcp-authoritative = true; - ra-param = "*,0,0"; - alias = "${publicIPv4},${dockerSwarmIPv4}"; - log-dhcp = true; - log-queries = true; - port = "5353"; - host-record = [ - "hermes.dmz,${dmzServicesIPv4},${dmzServicesIPv6}" - "ipv4.hermes.dmz,${dmzServicesIPv4}" - "ipv6.hermes.dmz,${dmzServicesIPv6}" - ]; - - server = [ - dmzRouterIPv4 - "/geokunis2.nl/${dmzServicesIPv4}" - "/kun.is/${dmzServicesIPv4}" - ]; - - dhcp-range = [ - "192.168.30.50,192.168.30.127,15m" - "2a0d:6e00:1a77:30::,ra-stateless,ra-names" - ]; - - dhcp-host = [ - "b8:27:eb:b9:ab:e2,esrom" - "ca:fe:c0:ff:ee:08,maestro,${dockerSwarmIPv4}" - ]; - - dhcp-option = [ - "3,${dmzRouterIPv4}" - "option:dns-server,${dmzRouterIPv4}" - "option6:dns-server,[2a02:58:19a:30::1]" - ]; - - address = [ - "/ns.pizzapim.nl/ns.geokunis2.nl/${dmzServicesIPv4}" - "/ns.pizzapim.nl/ns.geokunis2.nl/${dmzServicesIPv6}" - ]; -} diff --git a/nixos/modules/networking/dmz/default.nix b/nixos/modules/networking/dmz_services/default.nix similarity index 81% rename from nixos/modules/networking/dmz/default.nix rename to nixos/modules/networking/dmz_services/default.nix index 59fe536..c9eb235 100644 --- a/nixos/modules/networking/dmz/default.nix +++ b/nixos/modules/networking/dmz_services/default.nix @@ -1,6 +1,9 @@ +# TODO: we should split this into DHCP and DNS +# This decoupling makes it easier to put one service on another host. { pkgs, lib, config, dns, ... }@inputs: let - cfg = config.lab.networking.dmzServices; + cfg = config.lab.networking.dmz.services; + kunisZoneFile = pkgs.writeTextFile { name = "kunis-zone-file"; text = (dns.lib.toString "kun.is" (import ./zones/kun.is.nix inputs)); @@ -12,7 +15,7 @@ let }; in { - options.lab.networking.dmzServices.enable = lib.mkOption { + options.lab.networking.dmz.services.enable = lib.mkOption { default = false; type = lib.types.bool; description = '' @@ -21,7 +24,8 @@ in }; config = lib.mkIf cfg.enable { - lab.networking.allowDMZConnectivity = true; + # TODO Remove this; make this explicit in the machine config. + lab.networking.dmz.allowConnectivity = true; # TODO: listen only on dmz interface, make this portable between physical and VM. networking.firewall = { diff --git a/nixos/modules/networking/dmz_services/dnsmasq.nix b/nixos/modules/networking/dmz_services/dnsmasq.nix new file mode 100644 index 0000000..cbfe90d --- /dev/null +++ b/nixos/modules/networking/dmz_services/dnsmasq.nix @@ -0,0 +1,50 @@ +{ config, ... }: +let + cfg = config.lab.networking; +in +{ + no-resolv = true; + local = "/dmz/"; + dhcp-fqdn = true; + no-hosts = true; + expand-hosts = true; + domain = "dmz"; + dhcp-authoritative = true; + ra-param = "*,0,0"; + alias = "${cfg.public.ipv4.router},${cfg.dmz.ipv4.dockerSwarm}"; + log-dhcp = true; + log-queries = true; + port = "5353"; + host-record = [ + "hermes.dmz,${cfg.dmz.ipv4.services},${cfg.dmz.ipv6.services}" + "ipv4.hermes.dmz,${cfg.dmz.ipv4.services}" + "ipv6.hermes.dmz,${cfg.dmz.ipv6.services}" + ]; + + server = [ + cfg.dmz.ipv4.router + "/geokunis2.nl/${cfg.dmz.ipv4.services}" + "/kun.is/${cfg.dmz.ipv4.services}" + ]; + + dhcp-range = [ + "192.168.30.50,192.168.30.127,15m" + "2a0d:6e00:1a77:30::,ra-stateless,ra-names" + ]; + + dhcp-host = [ + "b8:27:eb:b9:ab:e2,esrom" + "ca:fe:c0:ff:ee:08,maestro,${cfg.dmz.ipv4.dockerSwarm}" + ]; + + dhcp-option = [ + "3,${cfg.dmz.ipv4.router}" + "option:dns-server,${cfg.dmz.ipv4.router}" + "option6:dns-server,[2a02:58:19a:30::1]" + ]; + + address = [ + "/ns.pizzapim.nl/ns.geokunis2.nl/${cfg.dmz.ipv4.services}" + "/ns.pizzapim.nl/ns.geokunis2.nl/${cfg.dmz.ipv6.services}" + ]; +} diff --git a/nixos/modules/networking/dmz/zones/geokunis2.nl.nix b/nixos/modules/networking/dmz_services/zones/geokunis2.nl.nix similarity index 51% rename from nixos/modules/networking/dmz/zones/geokunis2.nl.nix rename to nixos/modules/networking/dmz_services/zones/geokunis2.nl.nix index 65d8a40..3959b5f 100644 --- a/nixos/modules/networking/dmz/zones/geokunis2.nl.nix +++ b/nixos/modules/networking/dmz_services/zones/geokunis2.nl.nix @@ -1,7 +1,7 @@ { config, dns, ... }: with dns.lib.combinators; let - inherit (config.lab.networking) publicIPv4 dmzServicesIPv6 dockerSwarmIPv6 publicRouterIPv6; + cfg = config.lab.networking; in { SOA = { @@ -19,50 +19,50 @@ in MX = [ (mx.mx 10 "mail.geokunis2.nl.") ]; - A = [ publicIPv4 ]; - AAAA = [ dockerSwarmIPv6 ]; + A = [ cfg.public.ipv4.router ]; + AAAA = [ cfg.dmz.ipv6.dockerSwarm ]; CAA = letsEncrypt "caa@geokunis2.nl"; subdomains = { "*" = { - A = [ publicIPv4 ]; - AAAA = [ dockerSwarmIPv6 ]; + A = [ cfg.public.ipv4.router ]; + AAAA = [ cfg.dmz.ipv6.dockerSwarm ]; }; ns = { - A = [ publicIPv4 ]; - AAAA = [ dmzServicesIPv6 ]; + A = [ cfg.public.ipv4.router ]; + AAAA = [ cfg.dmz.ipv6.services ]; }; ns1 = { - A = [ publicIPv4 ]; - AAAA = [ dmzServicesIPv6 ]; + A = [ cfg.public.ipv4.router ]; + AAAA = [ cfg.dmz.ipv6.services ]; }; ns2 = { - A = [ publicIPv4 ]; - AAAA = [ dmzServicesIPv6 ]; + A = [ cfg.public.ipv4.router ]; + AAAA = [ cfg.dmz.ipv6.services ]; }; # Override because we don't support IPv6 for KMS. kms = { - A = [ publicIPv4 ]; + A = [ cfg.public.ipv4.router ]; AAAA = [ ]; }; wg = { - A = [ publicIPv4 ]; - AAAA = [ publicRouterIPv6 ]; + A = [ cfg.public.ipv4.router ]; + AAAA = [ cfg.public.ipv6.router ]; }; wg4 = { - A = [ publicIPv4 ]; + A = [ cfg.public.ipv4.router ]; AAAA = [ ]; }; wg6 = { A = [ ]; - AAAA = [ publicRouterIPv6 ]; + AAAA = [ cfg.public.ipv6.router ]; }; }; } diff --git a/nixos/modules/networking/dmz/zones/kun.is.nix b/nixos/modules/networking/dmz_services/zones/kun.is.nix similarity index 50% rename from nixos/modules/networking/dmz/zones/kun.is.nix rename to nixos/modules/networking/dmz_services/zones/kun.is.nix index 41ba5b7..364fec8 100644 --- a/nixos/modules/networking/dmz/zones/kun.is.nix +++ b/nixos/modules/networking/dmz_services/zones/kun.is.nix @@ -1,7 +1,7 @@ { config, dns, ... }: with dns.lib.combinators; let - inherit (config.lab.networking) publicIPv4 dmzServicesIPv6 dockerSwarmIPv6 publicRouterIPv6; + cfg = config.lab.networking; in { CAA = letsEncrypt "caa@kun.is"; @@ -23,41 +23,41 @@ in subdomains = { "*" = { - A = [ publicIPv4 ]; - AAAA = [ dockerSwarmIPv6 ]; + A = [ cfg.public.ipv4.router ]; + AAAA = [ cfg.dmz.ipv6.dockerSwarm ]; }; ns = { - A = [ publicIPv4 ]; - AAAA = [ dmzServicesIPv6 ]; + A = [ cfg.public.ipv4.router ]; + AAAA = [ cfg.dmz.ipv6.services ]; }; ns1 = { - A = [ publicIPv4 ]; - AAAA = [ dmzServicesIPv6 ]; + A = [ cfg.public.ipv4.router ]; + AAAA = [ cfg.dmz.ipv6.services ]; }; ns2 = { - A = [ publicIPv4 ]; - AAAA = [ dmzServicesIPv6 ]; + A = [ cfg.public.ipv4.router ]; + AAAA = [ cfg.dmz.ipv6.services ]; }; # Override because we don't support IPv6 for Git SSH. git = { - A = [ publicIPv4 ]; + A = [ cfg.public.ipv4.router ]; AAAA = [ ]; }; # Override because we don't support IPv6 for KMS. kms = { - A = [ publicIPv4 ]; + A = [ cfg.public.ipv4.router ]; AAAA = [ ]; }; - # Override because wg is on opnsense so ipv6 differs from "dmzServicesIPv6" + # Override because wg is on opnsense so ipv6 differs from "cfg.dmz.ipv6.services" wg = { - A = [ publicIPv4 ]; - AAAA = [ publicRouterIPv6 ]; + A = [ cfg.public.ipv4.router ]; + AAAA = [ cfg.dmz.ipv6.router ]; }; }; diff --git a/nixos/virtual.nix b/nixos/virtual.nix index 65dae01..14b6edc 100644 --- a/nixos/virtual.nix +++ b/nixos/virtual.nix @@ -51,44 +51,48 @@ networking.useDHCP = false; - systemd.network = { - enable = true; + systemd.network = + let + cfg = config.lab.networking; + in + { + enable = true; - networks = { - "30-main-nic" = { - matchConfig.Name = "en*"; + networks = { + "30-main-nic" = { + matchConfig.Name = "en*"; - networkConfig = { - IPv6AcceptRA = ! config.lab.vm.staticNetworking; - DHCP = lib.mkIf (! config.lab.vm.staticNetworking) "yes"; + networkConfig = { + IPv6AcceptRA = ! config.lab.vm.staticNetworking; + DHCP = lib.mkIf (! config.lab.vm.staticNetworking) "yes"; - Address = lib.mkIf config.lab.vm.staticNetworking [ - "${config.lab.vm.staticIPv4}/${config.lab.networking.dmzIPv4PrefixLength}" - "${config.lab.vm.staticIPv6}/${config.lab.networking.dmzIPv6PrefixLength}" - ]; + Address = lib.mkIf config.lab.vm.staticNetworking [ + "${ config.lab.vm.staticIPv4}/${cfg.dmz.ipv4.prefixLength}" + "${config.lab.vm.staticIPv6}/${cfg.dmz.ipv6.prefixLength}" + ]; - DNS = lib.mkIf config.lab.vm.staticNetworking [ - config.lab.networking.dmzRouterIPv4 - config.lab.networking.dmzRouterIPv6 + DNS = lib.mkIf config.lab.vm.staticNetworking [ + cfg.dmz.ipv4.router + cfg.dmz.ipv6.router + ]; + }; + + routes = lib.mkIf config.lab.vm.staticNetworking [ + { + routeConfig = { + Gateway = cfg.dmz.ipv4.router; + Destination = "0.0.0.0/0"; + }; + } + { + routeConfig = { + Gateway = cfg.dmz.ipv6.router; + Destination = "::/0"; + }; + } ]; }; - - routes = lib.mkIf config.lab.vm.staticNetworking [ - { - routeConfig = { - Gateway = config.lab.networking.dmzRouterIPv4; - Destination = "0.0.0.0/0"; - }; - } - { - routeConfig = { - Gateway = config.lab.networking.dmzRouterIPv6; - Destination = "::/0"; - }; - } - ]; }; }; - }; }; }