180 lines
6.0 KiB
Nix
180 lines
6.0 KiB
Nix
{ ... }:
|
|
{
|
|
_class = "clan.service";
|
|
manifest.name = "clan-core/yggdrasil";
|
|
manifest.description = "Yggdrasil encrypted IPv6 routing overlay network";
|
|
manifest.readme = builtins.readFile ./README.md;
|
|
|
|
roles.default = {
|
|
description = "Placeholder role to apply the yggdrasil service";
|
|
interface =
|
|
{ lib, ... }:
|
|
{
|
|
options.extraMulticastInterfaces = lib.mkOption {
|
|
type = lib.types.listOf lib.types.attrs;
|
|
default = [ ];
|
|
description = ''
|
|
Additional interfaces to use for Multicast. See
|
|
https://yggdrasil-network.github.io/configurationref.html#multicastinterfaces
|
|
for reference.
|
|
'';
|
|
example = [
|
|
{
|
|
Regex = "(wg).*";
|
|
Beacon = true;
|
|
Listen = true;
|
|
Port = 5400;
|
|
Priority = 1020;
|
|
}
|
|
];
|
|
};
|
|
|
|
options.extraPeers = lib.mkOption {
|
|
type = lib.types.listOf lib.types.str;
|
|
default = [ ];
|
|
description = ''
|
|
Additional static peers to configure for this host. If you use a
|
|
VPN clan service, it will automatically be added as peers to other hosts.
|
|
Local peers are also auto-discovered and don't need to be added.
|
|
'';
|
|
example = [
|
|
"tcp://192.168.1.1:6443"
|
|
"quic://192.168.1.1:6443"
|
|
"tls://192.168.1.1:6443"
|
|
"ws://192.168.1.1:6443"
|
|
];
|
|
};
|
|
};
|
|
perInstance =
|
|
{
|
|
settings,
|
|
roles,
|
|
exports,
|
|
...
|
|
}:
|
|
{
|
|
nixosModule =
|
|
{
|
|
config,
|
|
pkgs,
|
|
lib,
|
|
clan-core,
|
|
...
|
|
}:
|
|
let
|
|
|
|
mkPeers = ip: [
|
|
# "tcp://${ip}:6443"
|
|
"quic://${ip}:6443"
|
|
"ws://${ip}:6443"
|
|
"tls://${ip}:6443"
|
|
];
|
|
|
|
select' = clan-core.inputs.nix-select.lib.select;
|
|
|
|
# TODO make it nicer @lassulus, @picnoir wants microlens
|
|
# Get a list of all exported IPs from all VPN modules
|
|
exportedPeerIPs = builtins.foldl' (
|
|
acc: e:
|
|
if e == { } then
|
|
acc
|
|
else
|
|
acc ++ (lib.flatten (builtins.filter (s: s != "") (lib.attrValues (select' "peers.*.plain" e))))
|
|
) [ ] (lib.attrValues (select' "instances.*.networking.?peers.*.host.?plain" exports));
|
|
|
|
# Construct a list of peers in yggdrasil format
|
|
exportedPeers = lib.flatten (map mkPeers exportedPeerIPs);
|
|
|
|
in
|
|
{
|
|
|
|
# Set <yggdrasil ip> <hostname>.<tld> for all hosts.
|
|
# Networking modules will then add themselves as peers, so we can
|
|
# always use this to resolve a host via the best possible route,
|
|
# doing fail-over if needed.
|
|
networking.extraHosts = lib.strings.concatStringsSep "\n" (
|
|
lib.filter (n: n != "") (
|
|
map (
|
|
name:
|
|
let
|
|
ipPath = "${config.clan.core.settings.directory}/vars/per-machine/${name}/yggdrasil/address/value";
|
|
in
|
|
if builtins.pathExists ipPath then
|
|
"${builtins.readFile ipPath} ${name}.${config.clan.core.settings.tld}"
|
|
else
|
|
""
|
|
) (lib.attrNames roles.default.machines)
|
|
)
|
|
);
|
|
|
|
clan.core.vars.generators.yggdrasil = {
|
|
|
|
files.privateKey = { };
|
|
files.publicKey.secret = false;
|
|
files.address.secret = false;
|
|
|
|
runtimeInputs = with pkgs; [
|
|
yggdrasil
|
|
jq
|
|
openssl
|
|
];
|
|
|
|
script = ''
|
|
# Generate private key
|
|
openssl genpkey -algorithm Ed25519 -out $out/privateKey
|
|
|
|
# Generate corresponding public key
|
|
openssl pkey -in $out/privateKey -pubout -out $out/publicKey
|
|
|
|
# Derive IPv6 address from key
|
|
echo "{\"PrivateKeyPath\": \"$out/privateKey\"}" | yggdrasil -useconf -address | tr -d '\n' > $out/address
|
|
'';
|
|
};
|
|
|
|
systemd.services.yggdrasil.serviceConfig.BindReadOnlyPaths = [
|
|
"%d/key:/key"
|
|
];
|
|
|
|
systemd.services.yggdrasil.serviceConfig.LoadCredential =
|
|
"key:${config.clan.core.vars.generators.yggdrasil.files.privateKey.path}";
|
|
|
|
services.yggdrasil = {
|
|
enable = true;
|
|
openMulticastPort = true;
|
|
# We don't need this option, because we persist our keys with
|
|
# vars by ourselves. This option creates an unnecesary additional
|
|
# systemd service to save/load the keys and should be removed
|
|
# from the NixOS module entirely, as it can be replaced by the
|
|
# (at the time of writing undocumented) PrivateKeyPath= setting.
|
|
# See https://github.com/NixOS/nixpkgs/pull/440910#issuecomment-3301835895 for details.
|
|
persistentKeys = false;
|
|
settings = {
|
|
PrivateKeyPath = "/key";
|
|
IfName = "ygg";
|
|
Peers = lib.lists.unique (exportedPeers ++ settings.extraPeers);
|
|
MulticastInterfaces = [
|
|
# Ethernet is preferred over WIFI
|
|
{
|
|
Regex = "(eth|en).*";
|
|
Beacon = true;
|
|
Listen = true;
|
|
Port = 5400;
|
|
Priority = 1024;
|
|
}
|
|
{
|
|
Regex = "(wl).*";
|
|
Beacon = true;
|
|
Listen = true;
|
|
Port = 5400;
|
|
Priority = 1025;
|
|
}
|
|
]
|
|
++ settings.extraMulticastInterfaces;
|
|
};
|
|
};
|
|
networking.firewall.allowedTCPPorts = [ 5400 ];
|
|
};
|
|
};
|
|
};
|
|
}
|