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