1
0
mirror of https://github.com/ellmau/nixos.git synced 2025-12-19 09:29:36 +01:00

Add wireguard base config

module provided by Maximilian Marx

Co-authored-by: Maximilian Marx <maximilian.marx@tu-dresden.de>
This commit is contained in:
Stefan Ellmauthaler 2022-07-31 11:20:03 +02:00
parent f31d57b6f2
commit 95501e7f77
Signed by: ellmau
GPG Key ID: C804A9C1B7AF8256
2 changed files with 235 additions and 81 deletions

View File

@ -1,18 +1,33 @@
{ config, pkgs, lib, ... }:
with lib; {
config.elss.wireguard.interfaces = {
ellmaunet = {
# cough @ name
config.elss.wireguard = {
interfaces = {
stelnet = {
servers = {
metis = {
localIP = "1";
publicKey = "bla";
localIp = "1";
extraIps = [ "142" ];
publicKey = ""; #TODO
endpoint = "metis.ellmauthaler.net:51820"; #TODO
};
};
peers = { };
prefix = {
ipv4 = "192.168.242.";
peers = { # TODO
stel = {
localIp = "142";
publicKey = "6ZwilfrS1J/dMYRnwIMcQ3cW0KtJdLRj5VnSOjwOpn8=";
};
};
prefixes = {
ipv4 = [ ]; # TODO
ipv6 = {
ula = [ ]; # TODO
gua = [ ];
};
serial = "2022073100";
};
};
};
};

View File

@ -1,23 +1,41 @@
{ config, pkgs, lib, ... }:
with lib; {
options.elss.wireguard = {
enable = mkEnableOption "Setup wireguard";
{ config, lib, pkgs, ... }:
{
options.elss.wireguard = with lib; {
enable = mkEnableOption "wireguard overlay network";
interfaces = mkOption {
default = { };
type = types.attrsOf
(types.submodule {
type = types.attrsOf (types.submodule {
options = {
servers = mkOption {
type = types.attrsOf (types.submodule {
options = {
localIP = mkOption {
localIp = mkOption {
type = types.str;
description = "local IP for the interface";
description = "local IP part for the interfaces";
};
publickey = mkOption {
extraIps = mkOption {
type = types.listOf types.str;
default = [ ];
description = "extra IPs to add to allowedIPs";
};
listenPort = mkOption {
type = types.port;
description = "Port to listen on";
default = 51820;
};
publicKey = mkOption {
type = types.str;
description = "Wireguard public key for the server";
description = "Wireguard public key for this peer";
};
endpoint = mkOption {
type = types.str;
description = "Wireguard endpoint for this peer.";
};
};
});
@ -28,59 +46,117 @@ with lib; {
options = {
localIp = mkOption {
type = types.str;
description = "local IP for the peer";
};
publickey = mkOption {
type = types.str;
description = "Wireguard public key for the peer";
};
};
});
description = "local IP part for the interfaces";
};
prefix = {
ipv4 = mkOption {
type = types.str;
description = "IPv4 prefix for wireguard address room";
};
};
port = mkOption {
listenPort = mkOption {
type = types.port;
description = "Port to use";
description = "Port to listen on";
default = 51820;
};
publicKey = mkOption {
type = types.str;
description = "Wireguard public key for this peer";
};
};
});
};
prefixes = {
ipv4 = mkOption {
type = types.listOf types.str;
description = "IPv4 prefixes to use for wireguard addressing";
};
ipv6 = {
ula = mkOption {
type = types.listOf types.str;
description =
"IPv6 prefixes to use for ULA wireguard addressing";
};
gua = mkOption {
type = types.listOf types.str;
description =
"IPv6 prefixes to use for GUA wireguard addressing";
};
};
serial = mkOption {
type = types.str;
description = "serial for the generated DNS zone";
};
};
};
});
};
};
config =
let
cfg = config.elss;
hostName = config.system.name;
secrets = ../machines
secretsFile = ../machines
+ builtins.toPath "/${hostName}/secrets/wireguard.yaml";
mkRemoveEmpty = lib.filter (interface: interface != "");
mkInterfaces = input: mkRemoveEmpty
((expr:
takeNonEmpty = lib.filter (interface: interface != "");
testInterface = predicate:
lib.mapAttrsToList
(interface: value: if (expr interface value) then interface else "")
cfg.wireguard.interfaces)
input);
mkPeerInterface = mkInterfaces (interface: value: builtins.hasAttr hostName value.peers);
mkServInterface = mkInterfaces (interface: value: builtins.hasAttr hostName value.servers);
interfaces = mkServInterface ++ mkPeerInterface;
(interface: value: if (predicate interface value) then interface else "")
cfg.wireguard.interfaces;
onlyInterfaces = predicate: takeNonEmpty (testInterface predicate);
peerInterfaces =
onlyInterfaces (interface: value: builtins.hasAttr hostName value.peers);
serverInterfaces = onlyInterfaces
(interface: value: builtins.hasAttr hostName value.servers);
interfaces = serverInterfaces ++ peerInterfaces;
mkAddresses = prefixes: localIp:
(map (prefix: "${prefix}.${localIp}/32") prefixes.ipv4)
++ (map (prefix: "${prefix}::${localIp}/128") prefixes.ipv6.ula)
++ (map (prefix: "${prefix}::${localIp}/128") prefixes.ipv6.gua);
mkServerAddresses = prefixes: serverIp:
(map (prefix: "${prefix}.${serverIp}") prefixes.ipv4)
++ (map (prefix: "${prefix}::${serverIp}") prefixes.ipv6.ula)
++ (map (prefix: "${prefix}::${serverIp}") prefixes.ipv6.gua);
mkInterfaceName = interface: "wg-${interface}";
mkInterfaceSops = interface: {
"wireguard-${interface}" = { sopsFile = secrets; };
mkServerPeer = prefixes: peer: {
allowedIPs = mkAddresses prefixes peer.localIp;
inherit (peer) publicKey;
};
mkConfig = hostName: interface: value:
mkPeerPeer = prefixes: peer: {
allowedIPs = (mkAddresses prefixes peer.localIp)
++ (lib.concatMap (mkAddresses prefixes) peer.extraIps);
persistentKeepalive = 25;
inherit (peer) publicKey endpoint;
};
mkPostSetup = name: prefixes: servers:
let
ifName = mkInterfaceName name;
serverIps = name: server: mkServerAddresses prefixes server.localIp;
dnsServers = lib.concatLists (lib.mapAttrsToList serverIps servers);
in
lib.concatStrings ([
''
${pkgs.systemd}/bin/resolvectl domain ${ifName} ${name}.${config.elss.dns.wgZone}
${pkgs.systemd}/bin/resolvectl default-route ${ifName} true
''
] ++ (map
(ip: ''
${pkgs.systemd}/bin/resolvectl dns ${ifName} ${ip}
'')
dnsServers));
mkInterfaceConfig = hostName: interface: value:
let
isServer = builtins.hasAttr hostName value.servers;
isPeer = builtins.hasAttr hostName value.peers;
curConf =
myConfig =
if isServer then
value.servers."${hostName}"
else
@ -89,17 +165,80 @@ with lib; {
assert lib.asserts.assertMsg
((isServer || isPeer) && !(isServer && isPeer))
"host must be either server or peer";
lib.nameValuepair (mkInterfaceName interface) (
{
lib.nameValuePair (mkInterfaceName interface) ({
privateKeyFile = sops.secrets."wireguard-${interface}".path;
listenPort = value.listenPort;
} // (if isServer then { } else if isPeer then {
}
ips = mkAddresses value.prefixes myConfig.localIp;
inherit (myConfig) listenPort;
} // (if isServer then {
peers = lib.mapAttrsToList (_: mkServerPeer value.prefixes) value.peers;
} else if isPeer then {
peers = lib.mapAttrsToList (_: mkPeerPeer value.prefixes) value.servers;
postSetup = mkPostSetup interface value.prefixes value.servers;
} else
{ }));
mkInterfaceSecret = interface: {
"wireguard-${interface}" = { sopsFile = secretsFile; };
};
mkListenPorts = hostName: interface: value:
if builtins.hasAttr hostName value.servers then
value.servers."${hostName}".listenPort
else if builtins.hasAttr hostName value.peers then
value.peers."${hostName}".listenPort
else
{ })
);
-1;
mkSysctl = hostName: interface: [
{
name = "net.ipv4.conf.${mkInterfaceName interface}.forwarding";
value = "1";
}
{
name = "net.ipv6.conf.${mkInterfaceName interface}.forwarding";
value = "1";
}
{
name = "net.ipv6.conf.all.forwarding";
value = "1";
}
];
in
mkIf cfg.wireguard.enable {
sops.secrets = lib.mkMerge (map mkInterfaceSops interfaces);
lib.mkIf cfg.wireguard.enable {
networking = {
wireguard.interfaces =
lib.mapAttrs' (mkInterfaceConfig hostName) cfg.wireguard.interfaces;
firewall = {
# allowedUDPPorts = lib.filter (port: port > 0)
# (lib.mapAttrsToList (mkListenPorts hostName) cfg.wireguard.interfaces);
allowedUDPPorts = lib.filter (port: port > 0) (map
(interface:
lib.attrByPath [ interface "servers" hostName "listenPort" ] (-1)
cfg.wireguard.interfaces)
serverInterfaces);
trustedInterfaces = map mkInterfaceName interfaces;
};
interfaces = lib.listToAttrs (map
(interface: {
name = mkInterfaceName interface;
value = { mtu = 1300; };
})
interfaces);
};
services.unbound.settings.server.interface = map mkInterfaceName serverInterfaces;
systemd.services = lib.listToAttrs (map
(interface: {
name = "wireguard-${mkInterfaceName interface}";
value = { serviceConfig.Restart = "on-failure"; };
})
interfaces);
boot.kernel.sysctl =
builtins.listToAttrs (lib.concatMap (mkSysctl hostName) serverInterfaces);
sops.secrets = lib.mkMerge (map mkInterfaceSecret interfaces);
};
}