From 7fd91a898b0d61f7c5e2d7c2b1fb5272c9b6d8af Mon Sep 17 00:00:00 2001 From: David Guibert Date: Thu, 16 Aug 2018 13:44:39 +0200 Subject: [PATCH 1/2] systemd-networkd: add support for wireguard netdev. --- nixos/modules/system/boot/networkd.nix | 64 ++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/nixos/modules/system/boot/networkd.nix b/nixos/modules/system/boot/networkd.nix index d6b446e9ac22..2109b0cb1594 100644 --- a/nixos/modules/system/boot/networkd.nix +++ b/nixos/modules/system/boot/networkd.nix @@ -55,6 +55,20 @@ let (assertMacAddress "MACAddress") ]; + checkWireGuard = checkUnitConfig "WireGuard" [ + (assertOnlyFields [ + "PrivateKey" "PrivateKeyFile" "ListenPort" "FwMark" + ]) + #(assertRange "ListenPort" 1 65535) # Or "auto" + ]; + + checkWireGuardPeer = checkUnitConfig "WireGuardPeer" [ + (assertOnlyFields [ + "PublicKey" "PresharedKey" "AllowedIPs" "Endpoint" "PersistentKeepalive" + ]) + # (assertRange "PersistentKeepalive" 1 65535) # defined as "nullOr int" + ]; + checkVlan = checkUnitConfig "VLAN" [ (assertOnlyFields ["Id" "GVRP" "MVRP" "LooseBinding" "ReorderHeader"]) (assertRange "Id" 0 4094) @@ -320,6 +334,29 @@ let ''; }; + wireguardConfig = mkOption { + default = {}; + example = { ListenPort="auto"; }; + type = types.addCheck (types.attrsOf unitOption) checkWireGuard; + description = '' + Each attribute in this set specifies an option in the + [WireGuard] section of the unit. See + systemd.netdev + 5 for details. + ''; + }; + + wireguardPeers = mkOption { + default = [ ]; + type = with types; listOf (submodule wireguardPeerOptions); + description = '' + Each attribute in this set specifies an option in the + [WireGuardPeer] section of the unit. See + systemd.netdev + 5 for details. + ''; + }; + vlanConfig = mkOption { default = {}; example = { Id = "4"; }; @@ -450,6 +487,23 @@ let }; }; + wireguardPeerOptions = { + options = { + wireguardPeerConfig = mkOption { + default = {}; + example = { }; + type = types.addCheck (types.attrsOf unitOption) checkWireGuardPeer; + description = '' + Each attribute in this set specifies an option in the + [WireGuardPeer] section of the unit. See + systemd.network + 5 for details. + ''; + }; + }; + }; + + networkOptions = commonNetworkOptions // { networkConfig = mkOption { @@ -732,6 +786,16 @@ let ${attrsToSection def.bondConfig} ''} + ${optionalString (def.wireguardConfig != { }) '' + [WireGuard] + ${attrsToSection def.wireguardConfig} + + ''} + ${flip concatMapStrings def.wireguardPeers (x: '' + [WireGuardPeer] + ${attrsToSection x.wireguardPeerConfig} + + '')} ${def.extraConfig} ''; }; From 0528816570bf5a80ee396c1eb171b4cefae5ca62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Baylac-Jacqu=C3=A9?= Date: Mon, 24 Jun 2019 17:36:08 +0200 Subject: [PATCH 2/2] systemd-networkd: add tests (cherry picked from commit ec073e41a0dc8273cd81cf61fa37004310120af2) --- nixos/modules/system/boot/networkd.nix | 42 +++++++++--- nixos/tests/all-tests.nix | 1 + nixos/tests/systemd-networkd-wireguard.nix | 80 ++++++++++++++++++++++ 3 files changed, 114 insertions(+), 9 deletions(-) create mode 100644 nixos/tests/systemd-networkd-wireguard.nix diff --git a/nixos/modules/system/boot/networkd.nix b/nixos/modules/system/boot/networkd.nix index 2109b0cb1594..f2060e21509c 100644 --- a/nixos/modules/system/boot/networkd.nix +++ b/nixos/modules/system/boot/networkd.nix @@ -55,18 +55,25 @@ let (assertMacAddress "MACAddress") ]; + # NOTE The PrivateKey directive is missing on purpose here, please + # do not add it to this list. The nix store is world-readable let's + # refrain ourselves from providing a footgun. checkWireGuard = checkUnitConfig "WireGuard" [ (assertOnlyFields [ - "PrivateKey" "PrivateKeyFile" "ListenPort" "FwMark" + "PrivateKeyFile" "ListenPort" "FwMark" ]) - #(assertRange "ListenPort" 1 65535) # Or "auto" + (assertRange "FwMark" 1 4294967295) ]; + # NOTE The PresharedKey directive is missing on purpose here, please + # do not add it to this list. The nix store is world-readable,let's + # refrain ourselves from providing a footgun. checkWireGuardPeer = checkUnitConfig "WireGuardPeer" [ (assertOnlyFields [ - "PublicKey" "PresharedKey" "AllowedIPs" "Endpoint" "PersistentKeepalive" + "PublicKey" "PresharedKeyFile" "AllowedIPs" + "Endpoint" "PersistentKeepalive" ]) - # (assertRange "PersistentKeepalive" 1 65535) # defined as "nullOr int" + (assertRange "PersistentKeepalive" 1 65535) ]; checkVlan = checkUnitConfig "VLAN" [ @@ -336,24 +343,41 @@ let wireguardConfig = mkOption { default = {}; - example = { ListenPort="auto"; }; + example = { + PrivateKeyFile = "/etc/wireguard/secret.key"; + ListenPort = 51820; + FwMark = 42; + }; type = types.addCheck (types.attrsOf unitOption) checkWireGuard; description = '' Each attribute in this set specifies an option in the - [WireGuard] section of the unit. See + [WireGuard] section of the unit. See systemd.netdev 5 for details. + Use PrivateKeyFile instead of + PrivateKey: the nix store is + world-readable. ''; }; wireguardPeers = mkOption { - default = [ ]; + default = []; + example = [ { wireguardPeerConfig={ + Endpoint = "192.168.1.1:51820"; + PublicKey = "27s0OvaBBdHoJYkH9osZpjpgSOVNw+RaKfboT/Sfq0g="; + PresharedKeyFile = "/etc/wireguard/psk.key"; + AllowedIPs = [ "10.0.0.1/32" ]; + PersistentKeepalive = 15; + };}]; type = with types; listOf (submodule wireguardPeerOptions); description = '' - Each attribute in this set specifies an option in the - [WireGuardPeer] section of the unit. See + Each item in this array specifies an option in the + [WireGuardPeer] section of the unit. See systemd.netdev 5 for details. + Use PresharedKeyFile instead of + PresharedKey: the nix store is + world-readable. ''; }; diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 45ddf27c85e9..a99ac401a8ca 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -253,6 +253,7 @@ in systemd = handleTest ./systemd.nix {}; systemd-confinement = handleTest ./systemd-confinement.nix {}; systemd-timesyncd = handleTest ./systemd-timesyncd.nix {}; + systemd-networkd-wireguard = handleTest ./systemd-networkd-wireguard.nix {}; pdns-recursor = handleTest ./pdns-recursor.nix {}; taskserver = handleTest ./taskserver.nix {}; telegraf = handleTest ./telegraf.nix {}; diff --git a/nixos/tests/systemd-networkd-wireguard.nix b/nixos/tests/systemd-networkd-wireguard.nix new file mode 100644 index 000000000000..f1ce1e791ce3 --- /dev/null +++ b/nixos/tests/systemd-networkd-wireguard.nix @@ -0,0 +1,80 @@ +let generateNodeConf = { lib, pkgs, config, privkpath, pubk, peerId, nodeId, ...}: { + imports = [ common/user-account.nix ]; + systemd.services.systemd-networkd.environment.SYSTEMD_LOG_LEVEL = "debug"; + networking.useNetworkd = true; + networking.firewall.enable = false; + virtualisation.vlans = [ 1 ]; + environment.systemPackages = with pkgs; [ wireguard-tools ]; + boot.extraModulePackages = [ config.boot.kernelPackages.wireguard ]; + systemd.network = { + enable = true; + netdevs = { + "90-wg0" = { + netdevConfig = { Kind = "wireguard"; Name = "wg0"; }; + wireguardConfig = { + PrivateKeyFile = privkpath ; + ListenPort = 51820; + FwMark = 42; + }; + wireguardPeers = [ {wireguardPeerConfig={ + Endpoint = "192.168.1.${peerId}:51820"; + PublicKey = pubk; + PresharedKeyFile = pkgs.writeText "psk.key" "yTL3sCOL33Wzi6yCnf9uZQl/Z8laSE+zwpqOHC4HhFU="; + AllowedIPs = [ "10.0.0.${peerId}/32" ]; + PersistentKeepalive = 15; + };}]; + }; + }; + networks = { + "99-nope" = { + matchConfig.Name = "eth*"; + linkConfig.Unmanaged = true; + }; + "90-wg0" = { + matchConfig = { Name = "wg0"; }; + address = [ "10.0.0.${nodeId}/32" ]; + routes = [ + { routeConfig = { Gateway = "10.0.0.${nodeId}"; Destination = "10.0.0.0/24"; }; } + ]; + }; + "90-eth1" = { + matchConfig = { Name = "eth1"; }; + address = [ "192.168.1.${nodeId}/24" ]; + }; + }; + }; + }; +in import ./make-test.nix ({pkgs, ... }: { + name = "networkd-wireguard"; + meta = with pkgs.stdenv.lib.maintainers; { + maintainers = [ ninjatrappeur ]; + }; + nodes = { + node1 = { pkgs, ... }@attrs: + let localConf = { + privkpath = pkgs.writeText "priv.key" "GDiXWlMQKb379XthwX0haAbK6hTdjblllpjGX0heP00="; + pubk = "iRxpqj42nnY0Qz8MAQbSm7bXxXP5hkPqWYIULmvW+EE="; + nodeId = "1"; + peerId = "2"; + }; + in generateNodeConf (attrs // localConf); + + node2 = { pkgs, ... }@attrs: + let localConf = { + privkpath = pkgs.writeText "priv.key" "eHxSI2jwX/P4AOI0r8YppPw0+4NZnjOxfbS5mt06K2k="; + pubk = "27s0OvaBBdHoJYkH9osZpjpgSOVNw+RaKfboT/Sfq0g="; + nodeId = "2"; + peerId = "1"; + }; + in generateNodeConf (attrs // localConf); + }; +testScript = '' + startAll; + $node1->waitForUnit('systemd-networkd-wait-online.service'); + $node2->waitForUnit('systemd-networkd-wait-online.service'); + $node1->succeed('ping -c 5 10.0.0.2'); + $node2->succeed('ping -c 5 10.0.0.1'); + # Is the fwmark set? + $node2->succeed('wg | grep -q 42'); +''; +})