From 70d95acddbde14b09c6d04bb46a0bf3f4a4ebc41 Mon Sep 17 00:00:00 2001 From: kat witch Date: Tue, 7 Sep 2021 03:51:37 +0100 Subject: [PATCH] modules/{wireguard{,-tf},bird,policyrouting}: Init from hexchen --- config/hosts/athame/nixos.nix | 1 + config/hosts/beltane/nixos.nix | 4 + config/hosts/daiyousei/nixos.nix | 8 ++ config/hosts/ostara/nixos.nix | 1 + config/hosts/rinnosuke/nixos.nix | 8 ++ config/hosts/samhain/nixos.nix | 1 + config/hosts/shinmyoumaru/nixos.nix | 2 +- config/hosts/yule/nixos.nix | 1 + config/modules/nixos/bird.nix | 176 +++++++++++++++++++++++++ config/modules/nixos/policyrouting.nix | 51 +++++++ config/modules/nixos/wireguard-tf.nix | 54 ++++++++ config/modules/nixos/wireguard.nix | 85 ++++++++++++ config/profiles/base/network.nix | 3 +- config/profiles/network.nix | 62 +++++++++ config/users/kat/nixos.nix | 2 +- nix/sources.json | 6 +- 16 files changed, 459 insertions(+), 6 deletions(-) create mode 100644 config/modules/nixos/bird.nix create mode 100644 config/modules/nixos/policyrouting.nix create mode 100644 config/modules/nixos/wireguard-tf.nix create mode 100644 config/modules/nixos/wireguard.nix create mode 100644 config/profiles/network.nix diff --git a/config/hosts/athame/nixos.nix b/config/hosts/athame/nixos.nix index 0b0cb4f9..0bc669e6 100644 --- a/config/hosts/athame/nixos.nix +++ b/config/hosts/athame/nixos.nix @@ -7,6 +7,7 @@ with lib; imports = with meta; [ profiles.hardware.hcloud-imperative + profiles.network users.kat.server users.kat.services.weechat services.filehost diff --git a/config/hosts/beltane/nixos.nix b/config/hosts/beltane/nixos.nix index f1e3d970..67862c15 100644 --- a/config/hosts/beltane/nixos.nix +++ b/config/hosts/beltane/nixos.nix @@ -112,6 +112,10 @@ with lib; }; }; }; + wireguard = { + enable = true; + tf.enable = true; + }; yggdrasil = { enable = true; pubkey = "d3e488574367056d3ae809b678f799c29ebfd5c7151bb1f4051775b3953e5f52"; diff --git a/config/hosts/daiyousei/nixos.nix b/config/hosts/daiyousei/nixos.nix index e716a7cf..b12a7764 100644 --- a/config/hosts/daiyousei/nixos.nix +++ b/config/hosts/daiyousei/nixos.nix @@ -2,6 +2,7 @@ imports = with meta; [ profiles.hardware.aarch64 profiles.hardware.oracle.ubuntu + profiles.network services.nginx services.keycloak services.glauth @@ -21,6 +22,13 @@ }; }; + network = { + yggdrasil = { + enable = true; + pubkey = "89771aa2f15fce6bbc3548f95be360cf59657d299837b10adf53944b54e8f121"; + }; + }; + services.nginx.virtualHosts = let splashy = pkgs.host-splash-site config.networking.hostName; diff --git a/config/hosts/ostara/nixos.nix b/config/hosts/ostara/nixos.nix index dd578167..1c9ceb38 100644 --- a/config/hosts/ostara/nixos.nix +++ b/config/hosts/ostara/nixos.nix @@ -7,6 +7,7 @@ with lib; imports = with meta; [ profiles.hardware.eeepc-1015pem + profiles.network services.kattv ]; diff --git a/config/hosts/rinnosuke/nixos.nix b/config/hosts/rinnosuke/nixos.nix index 4e43eff0..ec321951 100644 --- a/config/hosts/rinnosuke/nixos.nix +++ b/config/hosts/rinnosuke/nixos.nix @@ -1,6 +1,7 @@ { config, tf, meta, kw, pkgs, lib, sources, ... }: with lib; { imports = with meta; [ profiles.hardware.oracle.ubuntu + profiles.network services.knot services.nginx ]; @@ -19,6 +20,13 @@ }; }; + network = { + yggdrasil = { + enable = true; + pubkey = "d3db7b089f3cb2d33e18c77b8f9a5a08185798143822b219dbc938aa37d29310"; + }; + }; + services.nginx.virtualHosts = let splashy = pkgs.host-splash-site config.networking.hostName; diff --git a/config/hosts/samhain/nixos.nix b/config/hosts/samhain/nixos.nix index b3b3b9ab..908e8d6d 100644 --- a/config/hosts/samhain/nixos.nix +++ b/config/hosts/samhain/nixos.nix @@ -14,6 +14,7 @@ in profiles.hardware.ms-7b86 profiles.gui profiles.vfio + profiles.network profiles.cross.aarch64 profiles.cross.armv6l profiles.cross.armv7l diff --git a/config/hosts/shinmyoumaru/nixos.nix b/config/hosts/shinmyoumaru/nixos.nix index 15355d18..8fb69b83 100644 --- a/config/hosts/shinmyoumaru/nixos.nix +++ b/config/hosts/shinmyoumaru/nixos.nix @@ -5,7 +5,7 @@ imports = with meta; [ profiles.hardware.raspi - profiles.base + profiles.network services.dnscrypt-proxy services.dht22-exporter ./image.nix diff --git a/config/hosts/yule/nixos.nix b/config/hosts/yule/nixos.nix index bbd04ee6..8586af88 100644 --- a/config/hosts/yule/nixos.nix +++ b/config/hosts/yule/nixos.nix @@ -8,6 +8,7 @@ with lib; imports = with meta; [ profiles.hardware.v330-14arr profiles.gui + profiles.network users.kat.guiFull services.nginx services.restic diff --git a/config/modules/nixos/bird.nix b/config/modules/nixos/bird.nix new file mode 100644 index 00000000..f77cf902 --- /dev/null +++ b/config/modules/nixos/bird.nix @@ -0,0 +1,176 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + bcfg = config.network.bird; + cfg = config.network.bird.ospf; +in +{ + options.network.bird = { + routerId = mkOption { + type = types.nullOr types.str; + default = null; + description = "Router ID to use. Must be an IPv4 address."; + }; + kernel4Config = mkOption { + type = types.lines; + default = '' + ipv4 { + import none; + export filter { + if source = RTS_STATIC then reject; + accept; + }; + }; + scan time 15; + ''; + }; + kernel6Config = mkOption { + type = types.lines; + default = '' + ipv6 { + import none; + export filter { + if source = RTS_STATIC then reject; + accept; + }; + }; + scan time 15; + ''; + }; + staticRoutes4 = mkOption { + type = types.listOf types.str; + default = [ ]; + }; + extraStatic4 = mkOption { + type = types.lines; + default = ""; + }; + staticRoutes6 = mkOption { + type = types.listOf types.str; + default = [ ]; + }; + extraStatic6 = mkOption { + type = types.lines; + default = ""; + }; + }; + options.network.bird.ospf = { + enable = mkEnableOption "OSPF-based network routing"; + protocols = mkOption { + default = { }; + type = types.attrsOf (types.submodule { + options = { + version = mkOption { type = types.enum [ 2 3 ]; default = 2; }; + extra = mkOption { type = types.lines; default = ""; }; + areas = mkOption { + description = "areas to configure in bird"; + default = { }; + type = types.attrsOf (types.submodule { + options = { + extra = mkOption { type = types.lines; default = ""; }; + networks = mkOption { + description = "Definition of area IP ranges. This is used in summary LSA origination."; + type = types.listOf types.str; + default = [ ]; + }; + external = mkOption { + description = "Definition of external area IP ranges for NSSAs. This is used for NSSA-LSA translation."; + type = types.listOf types.str; + default = [ ]; + }; + interfaces = mkOption { + description = "Interfaces to assign to the area"; + type = types.attrsOf (types.submodule { + options = { + cost = mkOption { type = types.int; default = 10; }; + poll = mkOption { type = types.int; default = 20; }; + retransmit = mkOption { type = types.int; default = 5; }; + priority = mkOption { type = types.int; default = 1; }; + deadCount = mkOption { type = types.int; default = 4; }; + type = mkOption { + type = types.enum [ + null + "broadcast" + "bcast" + "pointopoint" + "ptp" + "nonbroadcast" + "nbma" + "pointomultipoint" + "ptmp" + ]; + default = null; + }; + extra = mkOption { type = types.lines; default = ""; }; + }; + }); + }; + }; + }); + }; + }; + }); + }; + }; + + config = mkIf cfg.enable { + services.bird2 = { + enable = true; + config = '' + ${optionalString (bcfg.routerId != null) "router id ${bcfg.routerId};"} + + protocol device { + scan time 10; + } + + protocol kernel kernel4 { + ${bcfg.kernel4Config} + } + protocol kernel kernel6 { + ${bcfg.kernel6Config} + } + + protocol static static4 { + ipv4 { import all; export none; }; + ${concatMapStringsSep "\n" (x: "route ${x};") bcfg.staticRoutes4} + ${bcfg.extraStatic4} + } + protocol static static6 { + ipv6 { import all; export none; }; + ${concatMapStringsSep "\n" (x: "route ${x};") bcfg.staticRoutes6} + ${bcfg.extraStatic6} + } + + ${concatStringsSep "\n" (mapAttrsToList (protoName: proto: '' + protocol ospf v${toString proto.version} ${protoName} { + ${concatStringsSep "\n" (mapAttrsToList (areaName: area: '' + area ${areaName} { + ${optionalString + (area.networks != []) + "networks { ${concatStringsSep "\n" (map (x: "${x};") area.networks)} };"} + ${optionalString + (area.external != []) + "external { ${concatStringsSep "\n" (map (x: "${x};") area.external)} };"} + ${concatStringsSep "\n" (mapAttrsToList (ifacePattern: iface: '' + interface "${ifacePattern}" { + cost ${toString iface.cost}; + poll ${toString iface.poll}; + retransmit ${toString iface.retransmit}; + priority ${toString iface.priority}; + dead count ${toString iface.deadCount}; + ${optionalString (iface.type != null) "type ${iface.type};"} + ${iface.extra} + }; + '') area.interfaces)} + ${area.extra} + }; + '') proto.areas)} + ${proto.extra} + } + '') cfg.protocols)} + ''; + }; + }; +} diff --git a/config/modules/nixos/policyrouting.nix b/config/modules/nixos/policyrouting.nix new file mode 100644 index 00000000..60c999d8 --- /dev/null +++ b/config/modules/nixos/policyrouting.nix @@ -0,0 +1,51 @@ +{ config, lib, ... }: + +with lib; + +let + cfg = config.networking.policyrouting; + + ruleOpts = { ... }: { + options = { + prio = mkOption { + type = types.int; + }; + rule = mkOption { + type = types.str; + }; + }; + }; + +in +{ + options = { + networking.policyrouting = { + enable = mkEnableOption "Declarative Policy-Routing"; + rules = mkOption { + type = with types; listOf (submodule ruleOpts); + default = [ ]; + }; + rules6 = mkOption { + type = with types; listOf (submodule ruleOpts); + default = [ ]; + }; + rules4 = mkOption { + type = with types; listOf (submodule ruleOpts); + default = [ ]; + }; + }; + }; + + config = mkIf cfg.enable { + networking.policyrouting.rules = [ + { rule = "lookup main"; prio = 32000; } + ]; + networking.localCommands = '' + set -x + ip -6 rule flush + ip -4 rule flush + ${concatMapStringsSep "\n" ({ prio, rule }: "ip -6 rule add ${rule} prio ${toString prio}") (cfg.rules ++ cfg.rules6)} + ${concatMapStringsSep "\n" ({ prio, rule }: "ip -4 rule add ${rule} prio ${toString prio}") (cfg.rules ++ cfg.rules4)} + ''; + }; +} diff --git a/config/modules/nixos/wireguard-tf.nix b/config/modules/nixos/wireguard-tf.nix new file mode 100644 index 00000000..0c148157 --- /dev/null +++ b/config/modules/nixos/wireguard-tf.nix @@ -0,0 +1,54 @@ +{ config, pkgs, lib, tf, ... }: with lib; let + inherit (tf.lib.tf) terraformSelf; + cfg = config.network.wireguard; + dataDir = toString tf.terraform.dataDir; +in { + options.network.wireguard.tf = { + enable = mkEnableOption "using terraform for wireguard module"; + }; + config = mkIf config.network.wireguard.tf.enable { + deploy.tf = { + resources = { + "${config.networking.hostName}-wgmesh-gen" = { + provider = "null"; + type = "resource"; + provisioners = singleton { + local-exec.command = let + wg = "${pkgs.buildPackages.wireguard}/bin/wg"; + in "${wg} genkey | tee ${dataDir + "/wg-private-${terraformSelf "id"}"} | ${wg} pubkey > ${dataDir + "/wg-public-${terraformSelf "id"}"}"; + }; + }; + "${config.networking.hostName}-wgmesh-public-key" = { + provider = "local"; + type = "file"; + dataSource = true; + inputs.filename = dataDir + "/wg-public-${tf.resources."${config.networking.hostName}-wgmesh-gen".refAttr "id"}"; + }; + }; + deploy.systems.${config.networking.hostName}.triggers.switch = { + wg = tf.resources."${config.networking.hostName}-wgmesh-public-key".refAttr "content"; + }; + }; + + secrets.files."${config.networking.hostName}-wgmesh-private-key" = rec { + source = dataDir + "/wg-private-${tf.resources."${config.networking.hostName}-wgmesh-gen".refAttr "id"}"; + text = source; + }; + + network.wireguard = { + magicNumber = mkDefault (hexToInt (substring 0 2 (builtins.hashString "sha256" config.networking.hostName))); + keyPath = config.secrets.files."${config.networking.hostName}-wgmesh-private-key".path; + pubkey = let + pubKeyRes = tf.resources."${config.networking.hostName}-wgmesh-public-key"; + in mkIf (tf.state.resources ? ${pubKeyRes.out.reference}) (removeSuffix "\n" (pubKeyRes.importAttr "content")); + publicAddress4 = mkDefault (if config.network.addresses.public.nixos.ipv4.enable then + config.network.addresses.public.nixos.ipv4.address + else if config.network.addresses.private.nixos.ipv4.enable then + config.network.addresses.private.nixos.ipv4.address else null); + publicAddress6 = mkDefault (if config.network.addresses.public.nixos.ipv6.enable then + config.network.addresses.public.nixos.ipv6.address + else if config.network.addresses.private.nixos.ipv6.enable then + config.network.addresses.private.nixos.ipv6.address else null); + }; + }; +} diff --git a/config/modules/nixos/wireguard.nix b/config/modules/nixos/wireguard.nix new file mode 100644 index 00000000..e5a65183 --- /dev/null +++ b/config/modules/nixos/wireguard.nix @@ -0,0 +1,85 @@ +{ config, lib, pkgs, nodes, name, ... }: + +with lib; + +let + cfg = config.network.wireguard; + hcfg = _: h: h.network.wireguard; + netHostsSelf = mapAttrs hcfg (filterAttrs (_: x: x.network.wireguard.enable or false) nodes); + netHosts = filterAttrs (n: x: n != name) netHostsSelf; +in +{ + options.network.wireguard = { + enable = mkEnableOption "semi-automatic wireguard mesh"; + magicNumber = mkOption { type = types.ints.u8; }; + prefixV4 = mkOption { + type = types.str; + default = "172.23.1"; + }; + prefixV6 = mkOption { + type = types.str; + default = "fe80:"; + }; + keyPath = mkOption { + type = types.str; + default = "/etc/wireguard/mesh"; + }; + pubkey = mkOption { + type = with types; nullOr str; + default = null; + }; + publicAddress4 = mkOption { + type = with types; nullOr str; + default = null; + }; + publicAddress6 = mkOption { + type = with types; nullOr str; + default = null; + }; + fwmark = mkOption { + type = with types; nullOr ints.u16; + default = null; + }; + mtu = mkOption { + type = types.ints.u16; + default = 1500; + }; + }; + + config = mkIf cfg.enable { + networking.wireguard.interfaces = mapAttrs' + (hname: hconf: + let + magicPort = 51820 + hconf.magicNumber + cfg.magicNumber; + iname = "wgmesh-${substring 0 8 hname}"; + in + nameValuePair iname { + allowedIPsAsRoutes = false; + privateKeyFile = cfg.keyPath; + ips = [ + "${cfg.prefixV4}.${toString cfg.magicNumber}/24" + "${cfg.prefixV6}:${toString cfg.magicNumber}/64" + ]; + listenPort = magicPort; + peers = optional (hconf.pubkey != null) { + publicKey = hconf.pubkey; + allowedIPs = [ "0.0.0.0/0" "::0/0" ]; + endpoint = with hconf; mkIf (publicAddress4 != null || publicAddress6 != null) ( + if (publicAddress4 != null) + then "${publicAddress4}:${toString magicPort}" + else "[${publicAddress6}]:${toString magicPort}" + ); + persistentKeepalive = with hconf; mkIf (publicAddress4 == null && publicAddress6 == null) 25; + }; + postSetup = '' + ip route add ${cfg.prefixV4}.${toString hconf.magicNumber}/32 dev ${iname} + ${optionalString (cfg.fwmark != null) "wg set ${iname} fwmark ${toString cfg.fwmark}"} + ip link set ${iname} mtu ${toString cfg.mtu} + ''; + } + ) + netHosts; + networking.firewall.allowedUDPPorts = + mapAttrsToList (_: hconf: 51820 + hconf.magicNumber + cfg.magicNumber) netHosts; + }; +} diff --git a/config/profiles/base/network.nix b/config/profiles/base/network.nix index b603abc4..d29ec4dd 100644 --- a/config/profiles/base/network.nix +++ b/config/profiles/base/network.nix @@ -1,9 +1,10 @@ { config, lib, ... }: with lib; { + networking.nftables.enable = true; + network = { enable = true; - nftables.enable = true; dns = { enable = mkDefault true; email = "acme@kittywit.ch"; diff --git a/config/profiles/network.nix b/config/profiles/network.nix new file mode 100644 index 00000000..43b56973 --- /dev/null +++ b/config/profiles/network.nix @@ -0,0 +1,62 @@ +{ config, lib, pkgs, ... }: + +{ + options.network = with lib; { + routeDefault = mkOption { + default = true; + type = types.bool; + }; + }; + + config = { + networking.firewall.extraCommands = "ip6tables -A INPUT -p 89 -i wgmesh-+ -j ACCEPT"; + networking.nftables.extraInput = '' + meta l4proto 89 iifname wgmesh-* accept + ''; + + networking.policyrouting = { + enable = true; + rules = [ + { rule = "lookup main suppress_prefixlength 0"; prio = 7000; } + { rule = "lookup 89 suppress_prefixlength 0"; prio = 8000; } + { rule = "from all fwmark 51820 lookup main"; prio = 9000; } + ] ++ (lib.optional config.network.routeDefault { rule = "not from all fwmark 51820 lookup 89"; prio = 9000; }); + }; + + network.wireguard = { + enable = true; + tf.enable = true; + fwmark = 51820; + }; + + network.bird = + let + mkKernel = version: '' + ipv${toString version} { + import all; + export filter { + if source = RTS_STATIC then reject; + accept; + }; + }; + kernel table 89; + scan time 15; + ''; + mkIgp = version: { + version = 3; + extra = "ipv${toString version} { import all; export all; };"; + areas."0".interfaces."wgmesh-*".cost = 100; + }; + in + { + routerId = "${config.network.wireguard.prefixV4}.${toString config.network.wireguard.magicNumber}"; + kernel4Config = mkKernel 4; + kernel6Config = mkKernel 6; + ospf = { + enable = true; + protocols.igp4 = mkIgp 4; + protocols.igp6 = mkIgp 6; + }; + }; + }; +} diff --git a/config/users/kat/nixos.nix b/config/users/kat/nixos.nix index 8eea8552..1b4299d4 100644 --- a/config/users/kat/nixos.nix +++ b/config/users/kat/nixos.nix @@ -8,7 +8,7 @@ "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCocjQqiDIvzq+Qu3jkf7FXw5piwtvZ1Mihw9cVjdVcsra3U2c9WYtYrA3rS50N3p00oUqQm9z1KUrvHzdE+03ZCrvaGdrtYVsaeoCuuvw7qxTQRbItTAEsfRcZLQ5c1v/57HNYNEsjVrt8VukMPRXWgl+lmzh37dd9w45cCY1QPi+JXQQ/4i9Vc3aWSe4X6PHOEMSBHxepnxm5VNHm4PObGcVbjBf0OkunMeztd1YYA9sEPyEK3b8IHxDl34e5t6NDLCIDz0N/UgzCxSxoz+YJ0feQuZtud/YLkuQcMxW2dSGvnJ0nYy7SA5DkW1oqcy6CGDndHl5StOlJ1IF9aGh0gGkx5SRrV7HOGvapR60RphKrR5zQbFFka99kvSQgOZqSB3CGDEQGHv8dXKXIFlzX78jjWDOBT67vA/M9BK9FS2iNnBF5x6shJ9SU5IK4ySxq8qvN7Us8emkN3pyO8yqgsSOzzJT1JmWUAx0tZWG/BwKcFBHfceAPQl6pwxx28TM3BTBRYdzPJLTkAy48y6iXW6UYdfAPlShy79IYjQtEThTuIiEzdzgYdros0x3PDniuAP0KOKMgbikr0gRa6zahPjf0qqBnHeLB6nHAfaVzI0aNbhOg2bdOueE1FX0x48sjKqjOpjlIfq4WeZp9REr2YHEsoLFOBfgId5P3BPtpBQ== cardno:000612078454" ]; shell = pkgs.zsh; - extraGroups = [ "wheel" "video" "systemd-journal" "plugdev" ]; + extraGroups = [ "wheel" "video" "systemd-journal" "plugdev" "bird2" ]; hashedPassword = "$6$i28yOXoo$/WokLdKds5ZHtJHcuyGrH2WaDQQk/2Pj0xRGLgS8UcmY2oMv3fw2j/85PRpsJJwCB2GBRYRK5LlvdTleHd3mB."; }; diff --git a/nix/sources.json b/nix/sources.json index 76926c48..953cfd24 100644 --- a/nix/sources.json +++ b/nix/sources.json @@ -171,10 +171,10 @@ "homepage": null, "owner": "arcnmx", "repo": "tf-nix", - "rev": "d57b4335aa35781420b7d064d3d77141004c44e9", - "sha256": "0xfl305yaz6xlgaz2jxp4qpibqsyh2hjgibvyxbqqcx0frs9bvya", + "rev": "604582c7e39c652a4e09c26849dff0fb6fed60da", + "sha256": "0a700hci5k2w6y72hnwxgkrd4vfs8y8cj85qi03n80m6r933v2wq", "type": "tarball", - "url": "https://github.com/arcnmx/tf-nix/archive/d57b4335aa35781420b7d064d3d77141004c44e9.tar.gz", + "url": "https://github.com/arcnmx/tf-nix/archive/604582c7e39c652a4e09c26849dff0fb6fed60da.tar.gz", "url_template": "https://github.com///archive/.tar.gz" } }