127 lines
3.5 KiB
Nix
127 lines
3.5 KiB
Nix
{ pkgs, lib, config, ... }:
|
|
|
|
with lib;
|
|
let
|
|
cfg = config.fudo.vpn;
|
|
|
|
generate-pubkey-pkg = name: privkey:
|
|
pkgs.runCommand "wireguard-${name}-pubkey" {
|
|
WIREGUARD_PRIVATE_KEY = privkey;
|
|
} ''
|
|
mkdir $out
|
|
PUBKEY=$(echo $WIREGUARD_PRIVATE_KEY | ${pkgs.wireguard-tools}/bin/wg pubkey)
|
|
echo $PUBKEY > $out/pubkey.key
|
|
'';
|
|
|
|
generate-client-config = privkey-file: server-pubkey: network: server-ip: listen-port: dns-servers: ''
|
|
[Interface]
|
|
Address = ${ip.networkMinIp network}
|
|
PrivateKey = ${fileContents privkey-file}
|
|
ListenPort = ${toString listen-port}
|
|
DNS = ${concatStringsSep ", " dns-servers}
|
|
|
|
[Peer]
|
|
PublicKey = ${server-pubkey}
|
|
Endpoint = ${server-ip}:${toString listen-port}
|
|
AllowedIps = 0.0.0.0/0, ::/0
|
|
PersistentKeepalive = 25
|
|
'';
|
|
|
|
generate-peer-entry = peer-name: peer-privkey-path: peer-allowed-ips: let
|
|
peer-pkg = generate-pubkey-pkg "client-${peer-name}" (fileContents peer-privkey-path);
|
|
pubkey-path = "${peer-pkg}/pubkey.key";
|
|
in {
|
|
publicKey = fileContents pubkey-path;
|
|
allowedIPs = peer-allowed-ips;
|
|
};
|
|
|
|
in {
|
|
options.fudo.vpn = with types; {
|
|
enable = mkEnableOption "Enable Fudo VPN";
|
|
|
|
network = mkOption {
|
|
type = str;
|
|
description = "Network range to assign this interface.";
|
|
default = "10.100.0.0/16";
|
|
};
|
|
|
|
private-key-file = mkOption {
|
|
type = str;
|
|
description = "Path to the secret key (generated with wg [genkey/pubkey]).";
|
|
example = "/path/to/secret.key";
|
|
};
|
|
|
|
listen-port = mkOption {
|
|
type = port;
|
|
description = "Port on which to listen for incoming connections.";
|
|
default = 51820;
|
|
};
|
|
|
|
dns-servers = mkOption {
|
|
type = listOf str;
|
|
description = "A list of dns servers to pass to clients.";
|
|
default = ["1.1.1.1" "8.8.8.8"];
|
|
};
|
|
|
|
server-ip = mkOption {
|
|
type = str;
|
|
description = "IP of this WireGuard server.";
|
|
};
|
|
|
|
peers = mkOption {
|
|
type = attrsOf str;
|
|
description = "A map of peers to shared private keys.";
|
|
default = {};
|
|
example = {
|
|
peer0 = "/path/to/priv.key";
|
|
};
|
|
};
|
|
};
|
|
|
|
config = mkIf cfg.enable {
|
|
environment.etc = let
|
|
peer-data = imap1 (i: peer:{
|
|
name = peer.name;
|
|
privkey-path = peer.privkey-path;
|
|
network-range = let
|
|
base = ip.intToIpv4
|
|
((ip.ipv4ToInt (ip.getNetworkBase cfg.network)) + (i * 256));
|
|
in "${base}/24";
|
|
}) (mapAttrsToList (name: privkey-path: {
|
|
name = name;
|
|
privkey-path = privkey-path;
|
|
}) cfg.peers);
|
|
|
|
server-pubkey-pkg = generate-pubkey-pkg "server-pubkey" (fileContents cfg.private-key-file);
|
|
|
|
server-pubkey = fileContents "${server-pubkey-pkg}/pubkey.key";
|
|
|
|
in listToAttrs
|
|
(map (peer: nameValuePair "wireguard/clients/${peer.name}.conf" {
|
|
mode = "0400";
|
|
user = "root";
|
|
group = "root";
|
|
text = generate-client-config
|
|
peer.privkey-path
|
|
server-pubkey
|
|
peer.network-range
|
|
cfg.server-ip
|
|
cfg.listen-port
|
|
cfg.dns-servers;
|
|
}) peer-data);
|
|
|
|
networking.wireguard = {
|
|
enable = true;
|
|
interfaces.wgtun0 = {
|
|
generatePrivateKeyFile = false;
|
|
ips = [ cfg.network ];
|
|
listenPort = cfg.listen-port;
|
|
peers = mapAttrsToList
|
|
(name: private-key: generate-peer-entry name private-key ["0.0.0.0/0" "::/0"])
|
|
cfg.peers;
|
|
privateKeyFile = cfg.private-key-file;
|
|
};
|
|
};
|
|
};
|
|
}
|