nixos/nebula: Refactor module to allow for multiple nebula services on the same machine

This commit is contained in:
Tim Van Baak 2021-02-28 18:31:42 -08:00
parent 9f9e7c181c
commit 9f1ebd0c10

View File

@ -5,18 +5,21 @@ with lib;
let let
cfg = config.services.nebula; cfg = config.services.nebula;
nebulaDesc = "Nebula VPN service";
format = pkgs.formats.yaml {}; format = pkgs.formats.yaml {};
configFile = format.generate "nebula-config.yml" cfg.settings;
nameToId = netName: "nebula-${netName}";
in in
{ {
# Interface # Interface
options.services.nebula = { options = {
enable = mkEnableOption nebulaDesc; services.nebula = {
networks = mkOption {
description = "Nebula network definitions.";
default = {};
type = types.attrsOf (types.submodule {
options = {
package = mkOption { package = mkOption {
type = types.package; type = types.package;
default = pkgs.nebula; default = pkgs.nebula;
@ -99,9 +102,9 @@ in
}; };
tun.device = mkOption { tun.device = mkOption {
type = types.str; type = types.nullOr types.str;
default = "nebula1"; default = null;
description = "Name of the tun device."; description = "Name of the tun device. Defaults to nebula.\${networkName}.";
}; };
firewall.outbound = mkOption { firewall.outbound = mkOption {
@ -118,7 +121,7 @@ in
example = ''[ { port = "any"; proto = "any"; host = "any"; } ]''; example = ''[ { port = "any"; proto = "any"; host = "any"; } ]'';
}; };
settings = { settings = mkOption {
type = format.type; type = format.type;
default = {}; default = {};
description = '' description = ''
@ -136,41 +139,49 @@ in
''; '';
}; };
}; };
});
};
};
};
# Implementation # Implementation
config = mkIf (cfg.networks != {}) {
config = mkIf cfg.enable { systemd.services = mkMerge (lib.mapAttrsToList (netName: netCfg:
services.nebula.settings = { let
networkId = nameToId netName;
settings = lib.recursiveUpdate {
pki = { pki = {
ca = cfg.ca; ca = netCfg.ca;
cert = cfg.cert; cert = netCfg.cert;
key = cfg.key; key = netCfg.key;
}; };
static_host_map = cfg.staticHostMap; static_host_map = netCfg.staticHostMap;
lighthouse = { lighthouse = {
am_lighthouse = cfg.isLighthouse; am_lighthouse = netCfg.isLighthouse;
hosts = cfg.lighthouses; hosts = netCfg.lighthouses;
}; };
listen = { listen = {
host = cfg.listen.host; host = netCfg.listen.host;
port = cfg.listen.port; port = netCfg.listen.port;
}; };
punchy = { punchy = {
punch = cfg.punch; punch = netCfg.punch;
}; };
tun = { tun = {
disabled = cfg.tun.disable; disabled = netCfg.tun.disable;
dev = cfg.tun.device; dev = if (netCfg.tun.device != null) then netCfg.tun.device else "nebula.${netName}";
}; };
firewall = { firewall = {
inbound = cfg.firewall.inbound; inbound = netCfg.firewall.inbound;
outbound = cfg.firewall.outbound; outbound = netCfg.firewall.outbound;
}; };
}; } netCfg.settings;
configFile = format.generate "nebula-config-${netName}.yml" settings;
in
{
# Create systemd service for Nebula. # Create systemd service for Nebula.
systemd.services.nebula = { "nebula@${netName}" = {
description = nebulaDesc; description = "Nebula VPN service for ${netName}";
after = [ "network.target" ]; after = [ "network.target" ];
before = [ "sshd.service" ]; before = [ "sshd.service" ];
wantedBy = [ "multi-user.target" ]; wantedBy = [ "multi-user.target" ];
@ -178,29 +189,35 @@ in
{ {
Type = "simple"; Type = "simple";
Restart = "always"; Restart = "always";
ExecStart = "${cfg.package}/bin/nebula -config ${configFile}"; ExecStart = "${netCfg.package}/bin/nebula -config ${configFile}";
} }
# The service needs to launch as root to access the tun device, if it's enabled. # The service needs to launch as root to access the tun device, if it's enabled.
(mkIf cfg.tun.disable { (mkIf netCfg.tun.disable {
User = "nebula"; User = networkId;
Group = "nebula"; Group = networkId;
}) })
]; ];
}; };
}) cfg.networks);
# Open the chosen port for UDP. # Open the chosen ports for UDP.
networking.firewall.allowedUDPPorts = [ cfg.listen.port ]; networking.firewall.allowedUDPPorts =
lib.unique (lib.mapAttrsToList (netName: netCfg: netCfg.listen.port) cfg.networks);
# Create the service user and its group. # Create the service users and groups.
users = mkIf cfg.tun.disable { users.users = mkMerge (lib.mapAttrsToList (netName: netCfg:
users.nebula = { mkIf netCfg.tun.disable {
group = "nebula"; ${nameToId netName} = {
description = "Nebula service user"; group = nameToId netName;
description = "Nebula service user for network ${netName}";
isSystemUser = true; isSystemUser = true;
packages = [ cfg.package ]; packages = [ netCfg.package ];
}; };
}) cfg.networks);
groups.nebula = {}; users.groups = mkMerge (lib.mapAttrsToList (netName: netCfg:
}; mkIf netCfg.tun.disable {
${nameToId netName} = {};
}) cfg.networks);
}; };
} }