From 8e279a1e711faa80428b7b835914092abc1f1435 Mon Sep 17 00:00:00 2001 From: pinpox Date: Mon, 1 Sep 2025 22:31:09 +0200 Subject: [PATCH] Add yggdrasil clanService --- clanServices/yggdrasil/README.md | 33 +++++ clanServices/yggdrasil/default.nix | 125 ++++++++++++++++++ clanServices/yggdrasil/flake-module.nix | 24 ++++ clanServices/yggdrasil/tests/vm/default.nix | 67 ++++++++++ .../tests/vm/sops/machines/peer1/key.json | 6 + .../tests/vm/sops/machines/peer2/key.json | 6 + .../vm/sops/secrets/peer1-age.key/secret | 15 +++ .../vm/sops/secrets/peer1-age.key/users/admin | 1 + .../vm/sops/secrets/peer2-age.key/secret | 15 +++ .../vm/sops/secrets/peer2-age.key/users/admin | 1 + .../tests/vm/sops/users/admin/key.json | 4 + .../peer1/state-version/version/value | 1 + .../per-machine/peer1/yggdrasil/address/value | 1 + .../peer1/yggdrasil/privateKey/machines/peer1 | 1 + .../peer1/yggdrasil/privateKey/secret | 19 +++ .../peer1/yggdrasil/privateKey/users/admin | 1 + .../peer1/yggdrasil/publicKey/value | 3 + .../peer2/state-version/version/value | 1 + .../per-machine/peer2/yggdrasil/address/value | 1 + .../peer2/yggdrasil/privateKey/machines/peer2 | 1 + .../peer2/yggdrasil/privateKey/secret | 19 +++ .../peer2/yggdrasil/privateKey/users/admin | 1 + .../peer2/yggdrasil/publicKey/value | 3 + docs/mkdocs.yml | 1 + 24 files changed, 350 insertions(+) create mode 100644 clanServices/yggdrasil/README.md create mode 100644 clanServices/yggdrasil/default.nix create mode 100644 clanServices/yggdrasil/flake-module.nix create mode 100644 clanServices/yggdrasil/tests/vm/default.nix create mode 100755 clanServices/yggdrasil/tests/vm/sops/machines/peer1/key.json create mode 100755 clanServices/yggdrasil/tests/vm/sops/machines/peer2/key.json create mode 100644 clanServices/yggdrasil/tests/vm/sops/secrets/peer1-age.key/secret create mode 120000 clanServices/yggdrasil/tests/vm/sops/secrets/peer1-age.key/users/admin create mode 100644 clanServices/yggdrasil/tests/vm/sops/secrets/peer2-age.key/secret create mode 120000 clanServices/yggdrasil/tests/vm/sops/secrets/peer2-age.key/users/admin create mode 100644 clanServices/yggdrasil/tests/vm/sops/users/admin/key.json create mode 100644 clanServices/yggdrasil/tests/vm/vars/per-machine/peer1/state-version/version/value create mode 100644 clanServices/yggdrasil/tests/vm/vars/per-machine/peer1/yggdrasil/address/value create mode 120000 clanServices/yggdrasil/tests/vm/vars/per-machine/peer1/yggdrasil/privateKey/machines/peer1 create mode 100644 clanServices/yggdrasil/tests/vm/vars/per-machine/peer1/yggdrasil/privateKey/secret create mode 120000 clanServices/yggdrasil/tests/vm/vars/per-machine/peer1/yggdrasil/privateKey/users/admin create mode 100644 clanServices/yggdrasil/tests/vm/vars/per-machine/peer1/yggdrasil/publicKey/value create mode 100644 clanServices/yggdrasil/tests/vm/vars/per-machine/peer2/state-version/version/value create mode 100644 clanServices/yggdrasil/tests/vm/vars/per-machine/peer2/yggdrasil/address/value create mode 120000 clanServices/yggdrasil/tests/vm/vars/per-machine/peer2/yggdrasil/privateKey/machines/peer2 create mode 100644 clanServices/yggdrasil/tests/vm/vars/per-machine/peer2/yggdrasil/privateKey/secret create mode 120000 clanServices/yggdrasil/tests/vm/vars/per-machine/peer2/yggdrasil/privateKey/users/admin create mode 100644 clanServices/yggdrasil/tests/vm/vars/per-machine/peer2/yggdrasil/publicKey/value diff --git a/clanServices/yggdrasil/README.md b/clanServices/yggdrasil/README.md new file mode 100644 index 000000000..73f7cab85 --- /dev/null +++ b/clanServices/yggdrasil/README.md @@ -0,0 +1,33 @@ +This module sets up [yggdrasil](https://yggdrasil-network.github.io/) across +your clan. + +Yggdrasil is designed to be a future-proof and decentralised alternative to +the structured routing protocols commonly used today on the internet. Inside +your clan, it will allow you to reach all of your machines. + +## Example Usage + +While you can specify statically configured peers for each host, yggdrasil does +auto-discovery of local peers. + +```nix +inventory = { + + machines = { + peer1 = { }; + peer2 = { }; + }; + + instances = { + yggdrasil = { + + # Deploy on all machines + roles.default.tags.all = { }; + + # Or individual hosts + roles.default.machines.peer1 = { }; + roles.default.machines.peer2 = { }; + }; + }; +}; +``` diff --git a/clanServices/yggdrasil/default.nix b/clanServices/yggdrasil/default.nix new file mode 100644 index 000000000..1cae1ecd6 --- /dev/null +++ b/clanServices/yggdrasil/default.nix @@ -0,0 +1,125 @@ +{ ... }: +{ + _class = "clan.service"; + manifest.name = "clan-core/yggdrasil"; + manifest.description = "Yggdrasil encrypted IPv6 routing overlay network"; + + roles.default = { + 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.peers = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = [ ]; + description = '' + Static peers to configure for this host. + If not set, local peers will be auto-discovered + ''; + 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, ... }: + { + nixosModule = + { + config, + pkgs, + ... + }: + { + + 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 ourselfs. This option creates an unnessesary 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 = settings.peers; + 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 ]; + }; + }; + }; +} diff --git a/clanServices/yggdrasil/flake-module.nix b/clanServices/yggdrasil/flake-module.nix new file mode 100644 index 000000000..e79eeab38 --- /dev/null +++ b/clanServices/yggdrasil/flake-module.nix @@ -0,0 +1,24 @@ +{ + self, + lib, + ... +}: +let + module = lib.modules.importApply ./default.nix { + inherit (self) packages; + }; +in +{ + clan.modules = { + yggdrasil = module; + }; + perSystem = + { ... }: + { + clan.nixosTests.yggdrasil = { + imports = [ ./tests/vm/default.nix ]; + + clan.modules.yggdrasil = module; + }; + }; +} diff --git a/clanServices/yggdrasil/tests/vm/default.nix b/clanServices/yggdrasil/tests/vm/default.nix new file mode 100644 index 000000000..cdde0acbb --- /dev/null +++ b/clanServices/yggdrasil/tests/vm/default.nix @@ -0,0 +1,67 @@ +{ + name = "yggdrasil"; + + clan = { + test.useContainers = false; + directory = ./.; + inventory = { + + machines.peer1 = { }; + machines.peer2 = { }; + + instances."yggdrasil" = { + module.name = "yggdrasil"; + module.input = "self"; + + # Assign the roles to the two machines + roles.default.machines.peer1 = { }; + roles.default.machines.peer2 = { }; + }; + }; + }; + + testScript = '' + start_all() + + # Wait for both machines to be ready + peer1.wait_for_unit("multi-user.target") + peer2.wait_for_unit("multi-user.target") + + # Check that yggdrasil service is running on both machines + peer1.wait_for_unit("yggdrasil") + peer2.wait_for_unit("yggdrasil") + peer1.succeed("systemctl is-active yggdrasil") + peer2.succeed("systemctl is-active yggdrasil") + + # Check that both machines have yggdrasil network interfaces + peer1.wait_until_succeeds("ip link show | grep -E 'ygg'", 30) + peer2.wait_until_succeeds("ip link show | grep -E 'ygg'", 30) + + # Get yggdrasil IPv6 addresses from both machines + peer1_ygg_ip = peer1.succeed("yggdrasilctl -json getself | jq -r '.address'").strip() + peer2_ygg_ip = peer2.succeed("yggdrasilctl -json getself | jq -r '.address'").strip() + + # Compare runtime addresses with saved addresses from vars + expected_peer1_ip = "${builtins.readFile ./vars/per-machine/peer1/yggdrasil/address/value}" + expected_peer2_ip = "${builtins.readFile ./vars/per-machine/peer2/yggdrasil/address/value}" + + print(f"peer1 yggdrasil IP: {peer1_ygg_ip}") + print(f"peer2 yggdrasil IP: {peer2_ygg_ip}") + print(f"peer1 expected IP: {expected_peer1_ip}") + print(f"peer2 expected IP: {expected_peer2_ip}") + + # Verify that runtime addresses match expected addresses + assert peer1_ygg_ip == expected_peer1_ip, f"peer1 runtime IP {peer1_ygg_ip} != expected IP {expected_peer1_ip}" + assert peer2_ygg_ip == expected_peer2_ip, f"peer2 runtime IP {peer2_ygg_ip} != expected IP {expected_peer2_ip}" + + # Wait a bit for the yggdrasil network to establish connectivity + import time + time.sleep(10) + + # Test connectivity: peer1 should be able to ping peer2 via yggdrasil + peer1.succeed(f"ping -6 -c 3 {peer2_ygg_ip}") + + # Test connectivity: peer2 should be able to ping peer1 via yggdrasil + peer2.succeed(f"ping -6 -c 3 {peer1_ygg_ip}") + ''; +} diff --git a/clanServices/yggdrasil/tests/vm/sops/machines/peer1/key.json b/clanServices/yggdrasil/tests/vm/sops/machines/peer1/key.json new file mode 100755 index 000000000..3e767aef0 --- /dev/null +++ b/clanServices/yggdrasil/tests/vm/sops/machines/peer1/key.json @@ -0,0 +1,6 @@ +[ + { + "publickey": "age1p8trv2dmpanl3gnzj294c4t5uysu7d6rfjncp5lmn6redyda8fns6p7kca", + "type": "age" + } +] diff --git a/clanServices/yggdrasil/tests/vm/sops/machines/peer2/key.json b/clanServices/yggdrasil/tests/vm/sops/machines/peer2/key.json new file mode 100755 index 000000000..ee0ebce7d --- /dev/null +++ b/clanServices/yggdrasil/tests/vm/sops/machines/peer2/key.json @@ -0,0 +1,6 @@ +[ + { + "publickey": "age107mprppm3r9u7f26e6t5mhtdny0h5ugfmfjy8kac2tw9nrh9a3ksex0xca", + "type": "age" + } +] diff --git a/clanServices/yggdrasil/tests/vm/sops/secrets/peer1-age.key/secret b/clanServices/yggdrasil/tests/vm/sops/secrets/peer1-age.key/secret new file mode 100644 index 000000000..1a175f7ac --- /dev/null +++ b/clanServices/yggdrasil/tests/vm/sops/secrets/peer1-age.key/secret @@ -0,0 +1,15 @@ +{ + "data": "ENC[AES256_GCM,data:jDEog7FFXl28Le3rh5VTiY0DFmLhIy2ZccFjuYWx+OQrKNEqTLI1fzaeMWIcgu6ln6wfGUk640d3IhmrF45MVZiJGkpkOU8UFx0=,iv:4oGaoxhFQwr9OQfdLL7y1N/gJo/uGkTPG/xicVprIAQ=,tag:Smu0/P2bQB66w+0J2Bjlxw==,type:str]", + "sops": { + "age": [ + { + "recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBpQ2hib2Mrb0plWUVwNWU5\nWmpxNlduaUVJckhuQlhQbUJpanloWGFLelJ3CjJJMlBGbGRTWEhGUHh2VVkzUzNa\nL3FGVkF3R3JJT051UTg4UlkwOHRNanMKLS0tIDVWcHU4NmFMUWp3STFTYmg5YmNp\nVzd1Uzg2Wkp5QnJ3V1Qyb2lwSXdBRDgK/V5lgw2TePhUC9ngW53ZapIMkcwPvJus\ns0jUYkStHXjsvEiN7BG8cG7/vRbLD8CnKXnmieM20mT6o7GHGfhHMg==\n-----END AGE ENCRYPTED FILE-----\n" + } + ], + "lastmodified": "2025-09-17T07:12:51Z", + "mac": "ENC[AES256_GCM,data:gy/1NFmpFz/tdhgU/Vr+xg46DUjy9ZbrAtCBnIxclwZLJ/fneBpblv8TFgdysY4Ay6jp1S/TOc8eyr+KLHMqcBlje09wd1ac/Y3ee6GccXitB+/c5ayuXX/ShVCdicsr/9COw7vfndAQPU8XIz6tdy0dbL7jgVTyViZW/P5CXEU=,iv:BQ/INwTTCshl5BVnJbVzHW8rwafERS6bKh2JAJsMv9s=,tag:QhsbjeEBivbl8fQLHjiKtQ==,type:str]", + "unencrypted_suffix": "_unencrypted", + "version": "3.10.2" + } +} diff --git a/clanServices/yggdrasil/tests/vm/sops/secrets/peer1-age.key/users/admin b/clanServices/yggdrasil/tests/vm/sops/secrets/peer1-age.key/users/admin new file mode 120000 index 000000000..9e21a9938 --- /dev/null +++ b/clanServices/yggdrasil/tests/vm/sops/secrets/peer1-age.key/users/admin @@ -0,0 +1 @@ +../../../users/admin \ No newline at end of file diff --git a/clanServices/yggdrasil/tests/vm/sops/secrets/peer2-age.key/secret b/clanServices/yggdrasil/tests/vm/sops/secrets/peer2-age.key/secret new file mode 100644 index 000000000..ae482f07f --- /dev/null +++ b/clanServices/yggdrasil/tests/vm/sops/secrets/peer2-age.key/secret @@ -0,0 +1,15 @@ +{ + "data": "ENC[AES256_GCM,data:1rVgSwg2qPHuXUOQCgOunaNYiBbsh99dZ2y0BV4TxzACwdb3lb6/XnLeDenLELOpKruZQoNJax/NziRr+VHzmh/TlQhNgTkS71A=,iv:Wi5/cFOETb1rhAYeyzkpppzSSm+S+8cCQYc7zkp74FY=,tag:JQHFZJwYMQH4jUqSw6Ld8Q==,type:str]", + "sops": { + "age": [ + { + "recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBGV3ZLZmNrejlvTFF6NDZW\nYmljS0VXQUtCR3IzMG9tMksvSllVVkIxVTEwCi9Fd1dBbmFlYmF2cE1raVJoS3RR\nWmxQY3RwanRZUE5aN1Q2SzhJOFU1elEKLS0tIG9RMElDMEo3TFJjU0RvU3FMQk12\nT1pNc1VjeUliejk3YmJ6d29zUU15aDQKuZ62Q/ywLrpyu1jB34OCPKQEDd150qH6\nHzyw+MasUlzKNs0ZrALwfhnCKiNb/Pq0Lu660Dx5/sFxI/TAqC7NGg==\n-----END AGE ENCRYPTED FILE-----\n" + } + ], + "lastmodified": "2025-09-17T07:13:24Z", + "mac": "ENC[AES256_GCM,data:N7mmiEZxinOgWdd7QcZBAumnWaApjlQVww4EzAQ1/JH5i8r8CIfPh/7lGMQntlJj5ob+UgrS96nl6XKdvs3Bt7z34zPq7KV3c0mSmclEctRfcZiG4F+rZ0QIMIRJjq7xJL/M9WupSn8Lgms7qHJMdJyHdDkw47bmXz3MIw9c9zo=,iv:ZYPoo5jTIGnZ1HcAWlr26gloVhSjfhwbO/xH5YCbgF0=,tag:UKMVMGEfqyfo04cIkuKD0A==,type:str]", + "unencrypted_suffix": "_unencrypted", + "version": "3.10.2" + } +} diff --git a/clanServices/yggdrasil/tests/vm/sops/secrets/peer2-age.key/users/admin b/clanServices/yggdrasil/tests/vm/sops/secrets/peer2-age.key/users/admin new file mode 120000 index 000000000..9e21a9938 --- /dev/null +++ b/clanServices/yggdrasil/tests/vm/sops/secrets/peer2-age.key/users/admin @@ -0,0 +1 @@ +../../../users/admin \ No newline at end of file diff --git a/clanServices/yggdrasil/tests/vm/sops/users/admin/key.json b/clanServices/yggdrasil/tests/vm/sops/users/admin/key.json new file mode 100644 index 000000000..e408aa96b --- /dev/null +++ b/clanServices/yggdrasil/tests/vm/sops/users/admin/key.json @@ -0,0 +1,4 @@ +{ + "publickey": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg", + "type": "age" +} diff --git a/clanServices/yggdrasil/tests/vm/vars/per-machine/peer1/state-version/version/value b/clanServices/yggdrasil/tests/vm/vars/per-machine/peer1/state-version/version/value new file mode 100644 index 000000000..115ab7a6a --- /dev/null +++ b/clanServices/yggdrasil/tests/vm/vars/per-machine/peer1/state-version/version/value @@ -0,0 +1 @@ +25.11 \ No newline at end of file diff --git a/clanServices/yggdrasil/tests/vm/vars/per-machine/peer1/yggdrasil/address/value b/clanServices/yggdrasil/tests/vm/vars/per-machine/peer1/yggdrasil/address/value new file mode 100644 index 000000000..1b73a9853 --- /dev/null +++ b/clanServices/yggdrasil/tests/vm/vars/per-machine/peer1/yggdrasil/address/value @@ -0,0 +1 @@ +200:fa3b:ad0e:6821:9a51:3ad5:62a4:9ab1 \ No newline at end of file diff --git a/clanServices/yggdrasil/tests/vm/vars/per-machine/peer1/yggdrasil/privateKey/machines/peer1 b/clanServices/yggdrasil/tests/vm/vars/per-machine/peer1/yggdrasil/privateKey/machines/peer1 new file mode 120000 index 000000000..3e5f3fae3 --- /dev/null +++ b/clanServices/yggdrasil/tests/vm/vars/per-machine/peer1/yggdrasil/privateKey/machines/peer1 @@ -0,0 +1 @@ +../../../../../../sops/machines/peer1 \ No newline at end of file diff --git a/clanServices/yggdrasil/tests/vm/vars/per-machine/peer1/yggdrasil/privateKey/secret b/clanServices/yggdrasil/tests/vm/vars/per-machine/peer1/yggdrasil/privateKey/secret new file mode 100644 index 000000000..9c3529dfa --- /dev/null +++ b/clanServices/yggdrasil/tests/vm/vars/per-machine/peer1/yggdrasil/privateKey/secret @@ -0,0 +1,19 @@ +{ + "data": "ENC[AES256_GCM,data:oLWxmCqCLyKCdN90eScYC4eMsY5mcpXexk03P+KfQX9hCUg7iOSv+BTujvAFuJA0z2Pgg7B/L0noYSImE3208gDC2exdZme+szpNwxD6oh1bBx5XuYGc/TDzEl7IdPrf1piuqCkWgD6wNb9aFVA9NB/CrNaszY8=,iv:pU8OGFwtqkxy0+iyhWaOnWdSVvaxYBUgnQwv89CTfKc=,tag:V/GVEvjEpeaf3Tl3XCVL7w==,type:str]", + "sops": { + "age": [ + { + "recipient": "age1p8trv2dmpanl3gnzj294c4t5uysu7d6rfjncp5lmn6redyda8fns6p7kca", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBidXZxMVg2bkFCekFza3FV\naGVJTjRSSnQrVkgyTVU4Vk9YZFR2Nk1Xcnl3ClNTZnJsR2xZc3hGRFA0NGp2L2Uy\nU2w0N1ZON0xQRXRKL0NId1J3dWNSeXcKLS0tIFlKNk5walJrM2FGM0ozYTBUNVN1\nNHd0N3g2VWFjTUZtbHExdmsvSjJQUGMKDHgRMyTf4CuoIRdsfl6TmPLgcjxHdR4N\nzNmnSmT6QXJr4gBQ7e/3zpMdq4sKzyAOjJPkQra8nJ/KvhpFwXkdtg==\n-----END AGE ENCRYPTED FILE-----\n" + }, + { + "recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB1L3hBYnNTdEhTK1M0TEUx\nM1BFb3IwWDZPc2tkN0JUNXRPWkhEWHpXaFFNCkFlZ3Ixb1hhVWMvUmpKdCtjbW5h\nTVpLSkdxUXI4SVE3MW5LZkFVSmM3dDgKLS0tICtKWGYzbFQ1VGQydktHSDVadVQy\nM3JTSGc0NWVHWGl4akV2VUNNVjVvT00KKmbkGJ2KclTBb7NI0MamWZnlWMaXscws\nYO261RHc/j4s3KdbWATklh2KTicKpgta0mh294Y+hKYLGgBpnXjtOw==\n-----END AGE ENCRYPTED FILE-----\n" + } + ], + "lastmodified": "2025-09-17T07:12:51Z", + "mac": "ENC[AES256_GCM,data:YG4k+PvsF0NVfjqKY/MBhCOwn9Kcn5orq8aD41X3NEPBT+wU5RlN0XqXhH2nkZ52ZHdCN84Ulbd4guwBcJcUtGvxqOpfE4SJ9RFE+SjYw+2+S9wlArQx5R5Zd+Sr+Rgtaip3moENbxETxHZazbEK3u5o0aXKrZvoXH2xgPRYUOg=,iv:lDnNELLpqykrsmoORMW7p6gF43C2QvPwf0PZep2pEo8=,tag:CZNOBx3Aeoq5WeDbANqFVw==,type:str]", + "unencrypted_suffix": "_unencrypted", + "version": "3.10.2" + } +} diff --git a/clanServices/yggdrasil/tests/vm/vars/per-machine/peer1/yggdrasil/privateKey/users/admin b/clanServices/yggdrasil/tests/vm/vars/per-machine/peer1/yggdrasil/privateKey/users/admin new file mode 120000 index 000000000..ca714e122 --- /dev/null +++ b/clanServices/yggdrasil/tests/vm/vars/per-machine/peer1/yggdrasil/privateKey/users/admin @@ -0,0 +1 @@ +../../../../../../sops/users/admin \ No newline at end of file diff --git a/clanServices/yggdrasil/tests/vm/vars/per-machine/peer1/yggdrasil/publicKey/value b/clanServices/yggdrasil/tests/vm/vars/per-machine/peer1/yggdrasil/publicKey/value new file mode 100644 index 000000000..b33a3fc63 --- /dev/null +++ b/clanServices/yggdrasil/tests/vm/vars/per-machine/peer1/yggdrasil/publicKey/value @@ -0,0 +1,3 @@ +-----BEGIN PUBLIC KEY----- +MCowBQYDK2VwAyEAguIpeMvvMtdilU6tsqdBClci2YUgBKEUPQ5ID55zOVY= +-----END PUBLIC KEY----- diff --git a/clanServices/yggdrasil/tests/vm/vars/per-machine/peer2/state-version/version/value b/clanServices/yggdrasil/tests/vm/vars/per-machine/peer2/state-version/version/value new file mode 100644 index 000000000..115ab7a6a --- /dev/null +++ b/clanServices/yggdrasil/tests/vm/vars/per-machine/peer2/state-version/version/value @@ -0,0 +1 @@ +25.11 \ No newline at end of file diff --git a/clanServices/yggdrasil/tests/vm/vars/per-machine/peer2/yggdrasil/address/value b/clanServices/yggdrasil/tests/vm/vars/per-machine/peer2/yggdrasil/address/value new file mode 100644 index 000000000..21e3706ed --- /dev/null +++ b/clanServices/yggdrasil/tests/vm/vars/per-machine/peer2/yggdrasil/address/value @@ -0,0 +1 @@ +200:3975:b69f:fd15:f39a:bf24:f644:432b \ No newline at end of file diff --git a/clanServices/yggdrasil/tests/vm/vars/per-machine/peer2/yggdrasil/privateKey/machines/peer2 b/clanServices/yggdrasil/tests/vm/vars/per-machine/peer2/yggdrasil/privateKey/machines/peer2 new file mode 120000 index 000000000..6370c90d4 --- /dev/null +++ b/clanServices/yggdrasil/tests/vm/vars/per-machine/peer2/yggdrasil/privateKey/machines/peer2 @@ -0,0 +1 @@ +../../../../../../sops/machines/peer2 \ No newline at end of file diff --git a/clanServices/yggdrasil/tests/vm/vars/per-machine/peer2/yggdrasil/privateKey/secret b/clanServices/yggdrasil/tests/vm/vars/per-machine/peer2/yggdrasil/privateKey/secret new file mode 100644 index 000000000..a5698f4b1 --- /dev/null +++ b/clanServices/yggdrasil/tests/vm/vars/per-machine/peer2/yggdrasil/privateKey/secret @@ -0,0 +1,19 @@ +{ + "data": "ENC[AES256_GCM,data:Ik+mzD41SwfGZrqGi5oy0u8ZS8qCKgV34aohIt7J/11S3ayhKKN8451cYPltGg+2i/+2DWRSkqYZsctgIahvthnvb30r91XHRUCtE3oT8iPOKwEuW2xnZBL2dK0qHrKFGn8B/o3Bl/+4cWuR5Jt9QHlN4oF3o50=,iv:a9mSIr7TT9im19P5XKiDGL71hMLfQE8IB6NV8WABZ+s=,tag:dVQ0HZdpbkcmFA37Il+VIw==,type:str]", + "sops": { + "age": [ + { + "recipient": "age107mprppm3r9u7f26e6t5mhtdny0h5ugfmfjy8kac2tw9nrh9a3ksex0xca", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB3WEtncHIrd2YrbHduUm4y\nYkh1U0NERDR0MzRNQXZ0elNMZzl0ZmJPMlVVCnJ1UC9uNnk0dC9JVzdReUxLZmdR\nMGIwSjBKUW8yQmQ1R3dqU29ZM2czMEUKLS0tIFpMM3l6YnVFRUtLOFRvSTBXRXU0\nQUJWNk5obzBINS90dWwybXlXdEZFZjgKrZtViJwgPpKT+Bhx6ymEhf6QmnMmZ6Jf\n3kIxzDWxGbxrDTrrdXm33gYs9bRvtXsTACRT3TRAKIwSjIV/ycCUBA==\n-----END AGE ENCRYPTED FILE-----\n" + }, + { + "recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSArY1A4blFZNjdTU3lGUFA3\nb1hscVhLVmtuQnJMS3VHZVVEOXBDRktXNVhjCkdLZEFFZXhubFJrZTU3RjRDN1lh\nVzgyd3E3a0NGTGh1N2lPQWZBVG9BaW8KLS0tIFN1eEhpMk5mUkNaL29MS2NlWDdP\nVXFtb3c0Y25MT3NLK0N2RStkY1R0MGsKLv8yOSl2iQx39JRJA/e0dOtIz7ZND0+o\nzmqxapD6pxbj8RGswj0szLrxaveWT6Vkmmy/a4fz35uw3xuF7uiJJA==\n-----END AGE ENCRYPTED FILE-----\n" + } + ], + "lastmodified": "2025-09-17T07:13:24Z", + "mac": "ENC[AES256_GCM,data:KCBHfavyg1U/Z1e3rr0jdHivUa5/rl42N/K6c0BR47srdYqcpAS+SWW6tH7kPI3EO+P7TgXVoGlmcXaKgrlRpe37eNzdAT6PJYm7rhe6rm2UgZ1yw/NFqA11p/i3dDbTzYHaHMNGGGg9t/BdT1tD0zCICfptGQnSSBx/BEmT3ak=,iv:GOk8/z1mLIVKxFX4ayt9HvA90gv0Af1KqcDbdJRUYu4=,tag:hJpOBFRESQXmE7iMqDqO6g==,type:str]", + "unencrypted_suffix": "_unencrypted", + "version": "3.10.2" + } +} diff --git a/clanServices/yggdrasil/tests/vm/vars/per-machine/peer2/yggdrasil/privateKey/users/admin b/clanServices/yggdrasil/tests/vm/vars/per-machine/peer2/yggdrasil/privateKey/users/admin new file mode 120000 index 000000000..ca714e122 --- /dev/null +++ b/clanServices/yggdrasil/tests/vm/vars/per-machine/peer2/yggdrasil/privateKey/users/admin @@ -0,0 +1 @@ +../../../../../../sops/users/admin \ No newline at end of file diff --git a/clanServices/yggdrasil/tests/vm/vars/per-machine/peer2/yggdrasil/publicKey/value b/clanServices/yggdrasil/tests/vm/vars/per-machine/peer2/yggdrasil/publicKey/value new file mode 100644 index 000000000..6128b5e9e --- /dev/null +++ b/clanServices/yggdrasil/tests/vm/vars/per-machine/peer2/yggdrasil/publicKey/value @@ -0,0 +1,3 @@ +-----BEGIN PUBLIC KEY----- +MCowBQYDK2VwAyEA40UksAF1BjKgbYTd3motmeXa/belhNOoRfaaPQTXy8E= +-----END PUBLIC KEY----- diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index dc0640939..083050abb 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -172,6 +172,7 @@ nav: - reference/clanServices/users.md - reference/clanServices/wifi.md - reference/clanServices/wireguard.md + - reference/clanServices/yggdrasil.md - reference/clanServices/zerotier.md - Community: community/services/index.md