summary refs log tree commit diff
diff options
context:
space:
mode:
authorMaximilian Bosch <maximilian@mbosch.me>2019-04-24 16:00:34 +0200
committerGitHub <noreply@github.com>2019-04-24 16:00:34 +0200
commit28a95c4f7f1c46399e8938d7f3e08169cda61191 (patch)
tree52698d81aa92f7c263829961090e2fa8c5da3a5f
parent072c69f1ff397ea75b77e253fb41c7a07f6cb1cd (diff)
parent06c83a14e1826694c0cda073e253a3ca785e1461 (diff)
downloadnixpkgs-28a95c4f7f1c46399e8938d7f3e08169cda61191.tar
nixpkgs-28a95c4f7f1c46399e8938d7f3e08169cda61191.tar.gz
nixpkgs-28a95c4f7f1c46399e8938d7f3e08169cda61191.tar.bz2
nixpkgs-28a95c4f7f1c46399e8938d7f3e08169cda61191.tar.lz
nixpkgs-28a95c4f7f1c46399e8938d7f3e08169cda61191.tar.xz
nixpkgs-28a95c4f7f1c46399e8938d7f3e08169cda61191.tar.zst
nixpkgs-28a95c4f7f1c46399e8938d7f3e08169cda61191.zip
Merge pull request #60138 from grahamc/wireguard-generate-key
wireguard: add generatePrivateKeyFile option + test
-rw-r--r--nixos/modules/services/networking/wireguard.nix83
-rw-r--r--nixos/tests/all-tests.nix1
-rw-r--r--nixos/tests/wireguard/generated.nix57
3 files changed, 132 insertions, 9 deletions
diff --git a/nixos/modules/services/networking/wireguard.nix b/nixos/modules/services/networking/wireguard.nix
index 41aff1480a0..dd3cb1af271 100644
--- a/nixos/modules/services/networking/wireguard.nix
+++ b/nixos/modules/services/networking/wireguard.nix
@@ -26,19 +26,28 @@ let
         type = with types; nullOr str;
         default = null;
         description = ''
-          Base64 private key generated by wg genkey.
+          Base64 private key generated by <command>wg genkey</command>.
 
           Warning: Consider using privateKeyFile instead if you do not
           want to store the key in the world-readable Nix store.
         '';
       };
 
+      generatePrivateKeyFile = mkOption {
+        default = false;
+        type = types.bool;
+        description = ''
+          Automatically generate a private key with
+          <command>wg genkey</command>, at the privateKeyFile location.
+        '';
+      };
+
       privateKeyFile = mkOption {
         example = "/private/wireguard_key";
         type = with types; nullOr str;
         default = null;
         description = ''
-          Private key file as generated by wg genkey.
+          Private key file as generated by <command>wg genkey</command>.
         '';
       };
 
@@ -124,8 +133,8 @@ let
         example = "rVXs/Ni9tu3oDBLS4hOyAUAa1qTWVA3loR8eL20os3I=";
         type = with types; nullOr str;
         description = ''
-          Base64 preshared key generated by wg genpsk. Optional,
-          and may be omitted. This option adds an additional layer of
+          Base64 preshared key generated by <command>wg genpsk</command>.
+          Optional, and may be omitted. This option adds an additional layer of
           symmetric-key cryptography to be mixed into the already existing
           public-key cryptography, for post-quantum resistance.
 
@@ -139,8 +148,8 @@ let
         example = "/private/wireguard_psk";
         type = with types; nullOr str;
         description = ''
-          File pointing to preshared key as generated by wg pensk. Optional,
-          and may be omitted. This option adds an additional layer of
+          File pointing to preshared key as generated by <command>wg pensk</command>.
+          Optional, and may be omitted. This option adds an additional layer of
           symmetric-key cryptography to be mixed into the already existing
           public-key cryptography, for post-quantum resistance.
         '';
@@ -182,9 +191,48 @@ let
 
   };
 
-  generateUnit = name: values:
+
+  generatePathUnit = name: values:
+    assert (values.privateKey == null);
+    assert (values.privateKeyFile != null);
+    nameValuePair "wireguard-${name}"
+      {
+        description = "WireGuard Tunnel - ${name} - Private Key";
+        requiredBy = [ "wireguard-${name}.service" ];
+        before = [ "wireguard-${name}.service" ];
+        pathConfig.PathExists = values.privateKeyFile;
+      };
+
+  generateKeyServiceUnit = name: values:
+    assert values.generatePrivateKeyFile;
+    nameValuePair "wireguard-${name}-key"
+      {
+        description = "WireGuard Tunnel - ${name} - Key Generator";
+        wantedBy = [ "wireguard-${name}.service" ];
+        requiredBy = [ "wireguard-${name}.service" ];
+        before = [ "wireguard-${name}.service" ];
+        path = with pkgs; [ wireguard ];
+
+        serviceConfig = {
+          Type = "oneshot";
+          RemainAfterExit = true;
+        };
+
+        script = ''
+          mkdir --mode 0644 -p "${dirOf values.privateKeyFile}"
+          if [ ! -f "${values.privateKeyFile}" ]; then
+            touch "${values.privateKeyFile}"
+            chmod 0600 "${values.privateKeyFile}"
+            wg genkey > "${values.privateKeyFile}"
+            chmod 0400 "${values.privateKeyFile}"
+          fi
+        '';
+      };
+
+
+  generateSetupServiceUnit = name: values:
     # exactly one way to specify the private key must be set
-    assert (values.privateKey != null) != (values.privateKeyFile != null);
+    #assert (values.privateKey != null) != (values.privateKeyFile != null);
     let privKey = if values.privateKeyFile != null then values.privateKeyFile else pkgs.writeText "wg-key" values.privateKey;
     in
     nameValuePair "wireguard-${name}"
@@ -279,10 +327,27 @@ in
 
   config = mkIf (cfg.interfaces != {}) {
 
+    assertions = (attrValues (
+        mapAttrs (name: value: {
+          assertion = (value.privateKey != null) != (value.privateKeyFile != null);
+          message = "Either networking.wireguard.interfaces.${name}.privateKey or networking.wireguard.interfaces.${name}.privateKeyFile must be set.";
+        }) cfg.interfaces))
+      ++ (attrValues (
+        mapAttrs (name: value: {
+          assertion = value.generatePrivateKeyFile -> (value.privateKey == null);
+          message = "networking.wireguard.interfaces.${name}.generatePrivateKey must not be set if networking.wireguard.interfaces.${name}.privateKey is set.";
+        }) cfg.interfaces));
+
+
     boot.extraModulePackages = [ kernel.wireguard ];
     environment.systemPackages = [ pkgs.wireguard-tools ];
 
-    systemd.services = mapAttrs' generateUnit cfg.interfaces;
+    systemd.services = (mapAttrs' generateSetupServiceUnit cfg.interfaces)
+      // (mapAttrs' generateKeyServiceUnit
+      (filterAttrs (name: value: value.generatePrivateKeyFile) cfg.interfaces));
+
+    systemd.paths = mapAttrs' generatePathUnit
+      (filterAttrs (name: value: value.privateKeyFile != null) cfg.interfaces);
 
   };
 
diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix
index 950eb01044f..bf6fd60b144 100644
--- a/nixos/tests/all-tests.nix
+++ b/nixos/tests/all-tests.nix
@@ -238,6 +238,7 @@ in
   vault = handleTest ./vault.nix {};
   virtualbox = handleTestOn ["x86_64-linux"] ./virtualbox.nix {};
   wireguard = handleTest ./wireguard {};
+  wireguard-generated = handleTest ./wireguard/generated.nix {};
   wordpress = handleTest ./wordpress.nix {};
   xautolock = handleTest ./xautolock.nix {};
   xdg-desktop-portal = handleTest ./xdg-desktop-portal.nix {};
diff --git a/nixos/tests/wireguard/generated.nix b/nixos/tests/wireguard/generated.nix
new file mode 100644
index 00000000000..897feafe3ff
--- /dev/null
+++ b/nixos/tests/wireguard/generated.nix
@@ -0,0 +1,57 @@
+import ../make-test.nix ({ pkgs, ...} : {
+  name = "wireguard-generated";
+  meta = with pkgs.stdenv.lib.maintainers; {
+    maintainers = [ ma27 grahamc ];
+  };
+
+  nodes = {
+    peer1 = {
+      networking.firewall.allowedUDPPorts = [ 12345 ];
+      networking.wireguard.interfaces.wg0 = {
+        ips = [ "10.10.10.1/24" ];
+        listenPort = 12345;
+        privateKeyFile = "/etc/wireguard/private";
+        generatePrivateKeyFile = true;
+
+      };
+    };
+
+    peer2 = {
+      networking.firewall.allowedUDPPorts = [ 12345 ];
+      networking.wireguard.interfaces.wg0 = {
+        ips = [ "10.10.10.2/24" ];
+        listenPort = 12345;
+        privateKeyFile = "/etc/wireguard/private";
+        generatePrivateKeyFile = true;
+      };
+    };
+  };
+
+  testScript = ''
+    startAll;
+
+    $peer1->waitForUnit("wireguard-wg0.service");
+    $peer2->waitForUnit("wireguard-wg0.service");
+
+    my ($retcode, $peer1pubkey) = $peer1->execute("wg pubkey < /etc/wireguard/private");
+    $peer1pubkey =~ s/\s+$//;
+    if ($retcode != 0) {
+      die "Could not read public key from peer1";
+    }
+
+    my ($retcode, $peer2pubkey) = $peer2->execute("wg pubkey < /etc/wireguard/private");
+    $peer2pubkey =~ s/\s+$//;
+    if ($retcode != 0) {
+      die "Could not read public key from peer2";
+    }
+
+    $peer1->succeed("wg set wg0 peer $peer2pubkey allowed-ips 10.10.10.2/32 endpoint 192.168.1.2:12345 persistent-keepalive 1");
+    $peer1->succeed("ip route replace 10.10.10.2/32 dev wg0 table main");
+
+    $peer2->succeed("wg set wg0 peer $peer1pubkey allowed-ips 10.10.10.1/32 endpoint 192.168.1.1:12345 persistent-keepalive 1");
+    $peer2->succeed("ip route replace 10.10.10.1/32 dev wg0 table main");
+
+    $peer1->succeed("ping -c1 10.10.10.2");
+    $peer2->succeed("ping -c1 10.10.10.1");
+  '';
+})