nixos/yggdrasil: change config priority, persistentKeys
Favor the configuration in "configFile" over "config" to allow "configFile" to override "config" without a system rebuild. Add a "persistentKeys" option to generate keys and addresses that persist across service restarts. This is useful for self-configuring boot media.
This commit is contained in:
parent
067ad3cc94
commit
ac97b19a2a
@ -1,55 +1,17 @@
|
|||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, pkgs, ... }:
|
||||||
with lib;
|
with lib;
|
||||||
let
|
let
|
||||||
|
keysPath = "/var/lib/yggdrasil/keys.json";
|
||||||
|
|
||||||
cfg = config.services.yggdrasil;
|
cfg = config.services.yggdrasil;
|
||||||
configProvided = (cfg.config != {});
|
configProvided = cfg.config != { };
|
||||||
configAsFile = (if configProvided then
|
configFileProvided = cfg.configFile != null;
|
||||||
toString (pkgs.writeTextFile {
|
|
||||||
name = "yggdrasil-conf";
|
|
||||||
text = builtins.toJSON cfg.config;
|
|
||||||
})
|
|
||||||
else null);
|
|
||||||
configFileProvided = (cfg.configFile != null);
|
|
||||||
generateConfig = (
|
|
||||||
if configProvided && configFileProvided then
|
|
||||||
"${pkgs.jq}/bin/jq -s add ${configAsFile} ${cfg.configFile}"
|
|
||||||
else if configProvided then
|
|
||||||
"cat ${configAsFile}"
|
|
||||||
else if configFileProvided then
|
|
||||||
"cat ${cfg.configFile}"
|
|
||||||
else
|
|
||||||
"${cfg.package}/bin/yggdrasil -genconf"
|
|
||||||
);
|
|
||||||
|
|
||||||
in {
|
in {
|
||||||
options = with types; {
|
options = with types; {
|
||||||
services.yggdrasil = {
|
services.yggdrasil = {
|
||||||
enable = mkEnableOption "the yggdrasil system service";
|
enable = mkEnableOption "the yggdrasil system service";
|
||||||
|
|
||||||
configFile = mkOption {
|
|
||||||
type = nullOr str;
|
|
||||||
default = null;
|
|
||||||
example = "/run/keys/yggdrasil.conf";
|
|
||||||
description = ''
|
|
||||||
A file which contains JSON configuration for yggdrasil.
|
|
||||||
|
|
||||||
You do not have to supply a complete configuration, as
|
|
||||||
yggdrasil will use default values for anything which is
|
|
||||||
omitted. If the encryption and signing keys are omitted,
|
|
||||||
yggdrasil will generate new ones each time the service is
|
|
||||||
started, resulting in a random IPv6 address on the yggdrasil
|
|
||||||
network each time.
|
|
||||||
|
|
||||||
If both this option and <option>config</option> are
|
|
||||||
supplied, they will be combined, with values from
|
|
||||||
<option>config</option> taking precedence.
|
|
||||||
|
|
||||||
You can use the command <code>nix-shell -p yggdrasil --run
|
|
||||||
"yggdrasil -genconf -json"</code> to generate a default
|
|
||||||
JSON configuration.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
config = mkOption {
|
config = mkOption {
|
||||||
type = attrs;
|
type = attrs;
|
||||||
default = {};
|
default = {};
|
||||||
@ -66,16 +28,21 @@ in {
|
|||||||
Configuration for yggdrasil, as a Nix attribute set.
|
Configuration for yggdrasil, as a Nix attribute set.
|
||||||
|
|
||||||
Warning: this is stored in the WORLD-READABLE Nix store!
|
Warning: this is stored in the WORLD-READABLE Nix store!
|
||||||
Therefore, it is not appropriate for private keys. If you
|
Therefore, it is not appropriate for private keys. If you
|
||||||
do not specify the keys, yggdrasil will generate a new set
|
wish to specify the keys, use <option>configFile</option>.
|
||||||
each time the service is started, creating a random IPv6
|
|
||||||
address on the yggdrasil network each time.
|
|
||||||
|
|
||||||
If you wish to specify the keys, use
|
If the <option>persistentKeys</option> is enabled then the
|
||||||
<option>configFile</option>. If both
|
keys that are generated during activation will override
|
||||||
<option>configFile</option> and <option>config</option> are
|
those in <option>config</option> or
|
||||||
supplied, they will be combined, with values from
|
<option>configFile</option>.
|
||||||
<option>config</option> taking precedence.
|
|
||||||
|
If no keys are specified then ephemeral keys are generated
|
||||||
|
and the Yggdrasil interface will have a random IPv6 address
|
||||||
|
each time the service is started, this is the default.
|
||||||
|
|
||||||
|
If both <option>configFile</option> and <option>config</option>
|
||||||
|
are supplied, they will be combined, with values from
|
||||||
|
<option>configFile</option> taking precedence.
|
||||||
|
|
||||||
You can use the command <code>nix-shell -p yggdrasil --run
|
You can use the command <code>nix-shell -p yggdrasil --run
|
||||||
"yggdrasil -genconf"</code> to generate default
|
"yggdrasil -genconf"</code> to generate default
|
||||||
@ -83,12 +50,21 @@ in {
|
|||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
configFile = mkOption {
|
||||||
|
type = nullOr path;
|
||||||
|
default = null;
|
||||||
|
example = "/run/keys/yggdrasil.conf";
|
||||||
|
description = ''
|
||||||
|
A file which contains JSON configuration for yggdrasil.
|
||||||
|
See the <option>config</option> option for more information.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
group = mkOption {
|
group = mkOption {
|
||||||
type = types.str;
|
type = types.str;
|
||||||
default = "root";
|
default = "root";
|
||||||
example = "wheel";
|
example = "wheel";
|
||||||
description =
|
description = "Group to grant acces to the Yggdrasil control socket.";
|
||||||
"Group to grant acces to the Yggdrasil control socket.";
|
|
||||||
};
|
};
|
||||||
|
|
||||||
openMulticastPort = mkOption {
|
openMulticastPort = mkOption {
|
||||||
@ -126,37 +102,64 @@ in {
|
|||||||
defaultText = "pkgs.yggdrasil";
|
defaultText = "pkgs.yggdrasil";
|
||||||
description = "Yggdrasil package to use.";
|
description = "Yggdrasil package to use.";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
persistentKeys = mkEnableOption ''
|
||||||
|
If enabled then keys will be generated once and Yggdrasil
|
||||||
|
will retain the same IPv6 address when the service is
|
||||||
|
restarted. Keys are stored at ${keysPath}.
|
||||||
|
'';
|
||||||
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable (let binYggdrasil = cfg.package + "/bin/yggdrasil";
|
||||||
assertions = [
|
in {
|
||||||
{ assertion = config.networking.enableIPv6;
|
assertions = [{
|
||||||
message = "networking.enableIPv6 must be true for yggdrasil to work";
|
assertion = config.networking.enableIPv6;
|
||||||
}
|
message = "networking.enableIPv6 must be true for yggdrasil to work";
|
||||||
];
|
}];
|
||||||
|
|
||||||
|
system.activationScripts.yggdrasil = mkIf cfg.persistentKeys ''
|
||||||
|
if [ ! -e ${keysPath} ]
|
||||||
|
then
|
||||||
|
mkdir -p ${builtins.dirOf keysPath}
|
||||||
|
${binYggdrasil} -genconf -json \
|
||||||
|
| ${pkgs.jq}/bin/jq \
|
||||||
|
'to_entries|map(select(.key|endswith("Key")))|from_entries' \
|
||||||
|
> ${keysPath}
|
||||||
|
chmod 600 ${keysPath}
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
|
||||||
systemd.services.yggdrasil = {
|
systemd.services.yggdrasil = {
|
||||||
description = "Yggdrasil Network Service";
|
description = "Yggdrasil Network Service";
|
||||||
path = [ cfg.package ] ++ optional (configProvided && configFileProvided) pkgs.jq;
|
|
||||||
bindsTo = [ "network-online.target" ];
|
bindsTo = [ "network-online.target" ];
|
||||||
after = [ "network-online.target" ];
|
after = [ "network-online.target" ];
|
||||||
wantedBy = [ "multi-user.target" ];
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
|
||||||
preStart = ''
|
preStart =
|
||||||
${generateConfig} | yggdrasil -normaliseconf -useconf > /run/yggdrasil/yggdrasil.conf
|
(if configProvided || configFileProvided || cfg.persistentKeys then
|
||||||
'';
|
"echo "
|
||||||
|
|
||||||
|
+ (lib.optionalString configProvided
|
||||||
|
"'${builtins.toJSON cfg.config}'")
|
||||||
|
+ (lib.optionalString configFileProvided "$(cat ${cfg.configFile})")
|
||||||
|
+ (lib.optionalString cfg.persistentKeys "$(cat ${keysPath})")
|
||||||
|
+ " | ${pkgs.jq}/bin/jq -s add | ${binYggdrasil} -normaliseconf -useconf"
|
||||||
|
else
|
||||||
|
"${binYggdrasil} -genconf") + " > /run/yggdrasil/yggdrasil.conf";
|
||||||
|
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
ExecStart = "${cfg.package}/bin/yggdrasil -useconffile /run/yggdrasil/yggdrasil.conf";
|
ExecStart =
|
||||||
|
"${binYggdrasil} -useconffile /run/yggdrasil/yggdrasil.conf";
|
||||||
ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
|
ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
|
||||||
Restart = "always";
|
Restart = "always";
|
||||||
|
|
||||||
Group = cfg.group;
|
Group = cfg.group;
|
||||||
RuntimeDirectory = "yggdrasil";
|
RuntimeDirectory = "yggdrasil";
|
||||||
RuntimeDirectoryMode = "0750";
|
RuntimeDirectoryMode = "0750";
|
||||||
BindReadOnlyPaths = mkIf configFileProvided
|
BindReadOnlyPaths = lib.optional configFileProvided cfg.configFile
|
||||||
[ "${cfg.configFile}" ];
|
++ lib.optional cfg.persistentKeys keysPath;
|
||||||
|
|
||||||
# TODO: as of yggdrasil 0.3.8 and systemd 243, yggdrasil fails
|
# TODO: as of yggdrasil 0.3.8 and systemd 243, yggdrasil fails
|
||||||
# to set up the network adapter when DynamicUser is set. See
|
# to set up the network adapter when DynamicUser is set. See
|
||||||
@ -191,6 +194,6 @@ in {
|
|||||||
|
|
||||||
# Make yggdrasilctl available on the command line.
|
# Make yggdrasilctl available on the command line.
|
||||||
environment.systemPackages = [ cfg.package ];
|
environment.systemPackages = [ cfg.package ];
|
||||||
};
|
});
|
||||||
meta.maintainers = with lib.maintainers; [ gazally ];
|
meta.maintainers = with lib.maintainers; [ gazally ehmry ];
|
||||||
}
|
}
|
||||||
|
@ -85,6 +85,7 @@ in import ./make-test-python.nix ({ pkgs, ...} : {
|
|||||||
MulticastInterfaces = [ "eth1" ];
|
MulticastInterfaces = [ "eth1" ];
|
||||||
LinkLocalTCPPort = 43210;
|
LinkLocalTCPPort = 43210;
|
||||||
};
|
};
|
||||||
|
persistentKeys = true;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user