From 9b0ff955fd5696656f385ce268541f45e7d84cd0 Mon Sep 17 00:00:00 2001 From: Aristid Breitkreuz Date: Mon, 17 Jul 2017 23:55:31 +0200 Subject: wireguard: allow not storing private keys in world-readable /nix/store (#27433) * wireguard: allow not storing private keys in world-readable /nix/store --- nixos/modules/services/networking/wireguard.nix | 85 +++++++++++++++++-------- 1 file changed, 60 insertions(+), 25 deletions(-) (limited to 'nixos/modules/services/networking') diff --git a/nixos/modules/services/networking/wireguard.nix b/nixos/modules/services/networking/wireguard.nix index 62ff708d244c..d5b21ef1a23b 100644 --- a/nixos/modules/services/networking/wireguard.nix +++ b/nixos/modules/services/networking/wireguard.nix @@ -23,8 +23,23 @@ let privateKey = mkOption { example = "yAnz5TF+lXXJte14tji3zlMNq+hd2rYUIgJBgB3fBmk="; - type = types.str; - description = "Base64 private key generated by wg genkey."; + type = with types; nullOr str; + default = null; + description = '' + Base64 private key generated by wg genkey. + + Warning: Consider using privateKeyFile instead if you do not + want to store the key in the world-readable Nix store. + ''; + }; + + privateKeyFile = mkOption { + example = "/private/wireguard_key"; + type = with types; nullOr str; + default = null; + description = '' + Private key file as generated by wg genkey. + ''; }; listenPort = mkOption { @@ -91,7 +106,22 @@ let example = "rVXs/Ni9tu3oDBLS4hOyAUAa1qTWVA3loR8eL20os3I="; type = with types; nullOr str; description = '' - base64 preshared key generated by wg genpsk. Optional, + Base64 preshared key generated by wg genpsk. 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. + + Warning: Consider using presharedKeyFile instead if you do not + want to store the key in the world-readable Nix store. + ''; + }; + + presharedKeyFile = mkOption { + default = null; + 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 symmetric-key cryptography to be mixed into the already existing public-key cryptography, for post-quantum resistance. @@ -134,54 +164,59 @@ let }; - generateConf = name: values: pkgs.writeText "wireguard-${name}.conf" '' - [Interface] - PrivateKey = ${values.privateKey} - ${optionalString (values.listenPort != null) "ListenPort = ${toString values.listenPort}"} - - ${concatStringsSep "\n\n" (map (peer: '' - [Peer] - PublicKey = ${peer.publicKey} - ${optionalString (peer.presharedKey != null) "PresharedKey = ${peer.presharedKey}"} - ${optionalString (peer.allowedIPs != []) "AllowedIPs = ${concatStringsSep ", " peer.allowedIPs}"} - ${optionalString (peer.endpoint != null) "Endpoint = ${peer.endpoint}"} - ${optionalString (peer.persistentKeepalive != null) "PersistentKeepalive = ${toString peer.persistentKeepalive}"} - '') values.peers)} - ''; - ipCommand = "${pkgs.iproute}/bin/ip"; wgCommand = "${pkgs.wireguard}/bin/wg"; generateUnit = name: values: + # exactly one way to specify the private key must be set + 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}" { description = "WireGuard Tunnel - ${name}"; after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; + serviceConfig = { Type = "oneshot"; RemainAfterExit = true; - ExecStart = lib.flatten([ + ExecStart = flatten([ values.preSetup "-${ipCommand} link del dev ${name}" "${ipCommand} link add dev ${name} type wireguard" - "${wgCommand} setconf ${name} ${generateConf name values}" (map (ip: - ''${ipCommand} address add ${ip} dev ${name}'' + "${ipCommand} address add ${ip} dev ${name}" ) values.ips) + ("${wgCommand} set ${name} private-key ${privKey}" + + optionalString (values.listenPort != null) " listen-port ${toString values.listenPort}") + + (map (peer: + assert (peer.presharedKeyFile == null) || (peer.presharedKey == null); # at most one of the two must be set + let psk = if peer.presharedKey != null then pkgs.writeText "wg-psk" peer.presharedKey else peer.presharedKeyFile; + in + "${wgCommand} set ${name} peer ${peer.publicKey}" + + optionalString (psk != null) " preshared-key ${psk}" + + optionalString (peer.endpoint != null) " endpoint ${peer.endpoint}" + + optionalString (peer.persistentKeepalive != null) " persistent-keepalive ${toString peer.persistentKeepalive}" + + optionalString (peer.allowedIPs != []) " allowed-ips ${concatStringsSep "," peer.allowedIPs}" + ) values.peers) + "${ipCommand} link set up dev ${name}" - (flatten (map (peer: (map (ip: + (map (peer: (map (ip: "${ipCommand} route add ${ip} dev ${name}" - ) peer.allowedIPs)) values.peers)) + ) peer.allowedIPs)) values.peers) values.postSetup ]); - - ExecStop = [ ''${ipCommand} link del dev "${name}"'' ] ++ values.postShutdown; + ExecStop = flatten([ + "${ipCommand} link del dev ${name}" + values.postShutdown + ]); }; }; -- cgit 1.4.1