add clanModule for zerotier inventory

This commit is contained in:
a-kenji
2024-08-28 10:54:40 +02:00
committed by Mic92
parent 085052a6ca
commit 8504a0e674
9 changed files with 184 additions and 6 deletions

View File

@@ -36,5 +36,6 @@
xfce = ./xfce;
zerotier-static-peers = ./zerotier-static-peers;
zt-tcp-relay = ./zt-tcp-relay;
zerotier = ./zerotier;
};
}

View File

@@ -0,0 +1,7 @@
---
description = "Statically configure the `zerotier` peers of a clan network."
features = [ "inventory" ]
---
Statically configure the `zerotier` peers of a clan network.
Requires a machine, that is the zerotier controller configured in the network.

View File

@@ -0,0 +1,2 @@
# TODO: only kept this file to not break documentation generation.
{ }

View File

@@ -0,0 +1,47 @@
{
config,
lib,
pkgs,
...
}:
let
instanceNames = builtins.attrNames config.clan.inventory.services.zerotier;
instanceName = builtins.head instanceNames;
zeroTierInstance = config.clan.inventory.services.zerotier.${instanceName};
roles = zeroTierInstance.roles;
stringSet = list: builtins.attrNames (builtins.groupBy lib.id list);
in
{
imports = [
../shared.nix
];
config = {
systemd.services.zerotier-inventory-autoaccept =
let
machines = stringSet (roles.moon.machines ++ roles.controller.machines ++ roles.peer.machines);
networkIps = builtins.foldl' (
ips: name:
if builtins.pathExists "${config.clan.core.clanDir}/machines/${name}/facts/zerotier-ip" then
ips
++ [
(builtins.readFile "${config.clan.core.clanDir}/machines/${name}/facts/zerotier-ip")
]
else
ips
) [ ] machines;
allHostIPs = config.clan.zerotier.networkIps ++ networkIps;
in
{
wantedBy = [ "multi-user.target" ];
after = [ "zerotierone.service" ];
path = [ config.clan.core.clanPkgs.zerotierone ];
serviceConfig.ExecStart = pkgs.writeShellScript "zerotier-inventory-autoaccept" ''
${lib.concatMapStringsSep "\n" (host: ''
${config.clan.core.clanPkgs.zerotier-members}/bin/zerotier-members allow --member-ip ${host}
'') allHostIPs}
'';
};
clan.core.networking.zerotier.controller.enable = lib.mkDefault true;
};
}

View File

@@ -0,0 +1,17 @@
{ config, lib, ... }:
{
imports = [
../shared.nix
];
options.clan.zerotier.moon.stableEndpoints = lib.mkOption {
type = lib.types.listOf lib.types.str;
description = ''
Make this machine a moon.
Other machines can join this moon by adding this moon in their config.
It will be reachable under the given stable endpoints.
'';
};
# TODO, we want to remove these options from clanCore
config.clan.core.networking.zerotier.moon.stableEndpoints =
config.clan.zerotier.moon.stableEndpoints;
}

View File

@@ -0,0 +1,5 @@
{
imports = [
../shared.nix
];
}

View File

@@ -0,0 +1,95 @@
{
lib,
config,
pkgs,
...
}:
let
instanceNames = builtins.attrNames config.clan.inventory.services.zerotier;
instanceName = builtins.head instanceNames;
zeroTierInstance = config.clan.inventory.services.zerotier.${instanceName};
roles = zeroTierInstance.roles;
controllerMachine = builtins.head roles.controller.machines;
networkIdPath = "${config.clan.core.clanDir}/machines/${controllerMachine}/facts/zerotier-network-id";
networkId = if builtins.pathExists networkIdPath then builtins.readFile networkIdPath else null;
moons = roles.moon.machines;
moonIps = builtins.foldl' (
ips: name:
if builtins.pathExists "${config.clan.core.clanDir}/machines/${name}/facts/zerotier-ip" then
ips
++ [
(builtins.readFile "${config.clan.core.clanDir}/machines/${name}/facts/zerotier-ip")
]
else
ips
) [ ] moons;
in
{
options.clan.zerotier = {
excludeHosts = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ config.clan.core.machineName ];
description = "Hosts that should be excluded";
};
networkIps = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ ];
description = "Extra zerotier network Ips that should be accepted";
};
networkIds = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ ];
description = "Extra zerotier network Ids that should be accepted";
};
};
config = {
assertions = [
{
assertion = builtins.length instanceNames == 1;
message = "The zerotier module currently only supports one instance per machine, but found ${builtins.toString instanceNames}";
}
{
assertion = builtins.length roles.controller.machines == 1;
message = "The zerotier module requires exactly one controller, but found ${builtins.toString roles.controller.machines}";
}
];
clan.core.networking.zerotier.networkId = networkId;
clan.core.networking.zerotier.name = instanceName;
# TODO: in future we want to have the node id of our moons in our facts
systemd.services.zerotierone.serviceConfig.ExecStartPost = lib.mkIf (moonIps != [ ]) (
lib.mkAfter [
"+${pkgs.writeScript "orbit-moons-by-ip" ''
#!${pkgs.python3.interpreter}
import json
import ipaddress
import subprocess
def compute_member_id(ipv6_addr: str) -> str:
addr = ipaddress.IPv6Address(ipv6_addr)
addr_bytes = bytearray(addr.packed)
# Extract the bytes corresponding to the member_id (node_id)
node_id_bytes = addr_bytes[10:16]
node_id = int.from_bytes(node_id_bytes, byteorder="big")
member_id = format(node_id, "x").zfill(10)[-10:]
return member_id
def main() -> None:
ips = json.loads(${builtins.toJSON (builtins.toJSON moonIps)})
for ip in ips:
member_id = compute_member_id(ip)
res = subprocess.run(["zerotier-cli", "orbit", member_id, member_id])
if res.returncode != 0:
print(f"Failed to add {member_id} to orbit")
if __name__ == "__main__":
main()
''}"
]
);
};
}

View File

@@ -66,22 +66,23 @@ nav:
- Reference:
- Overview: reference/index.md
- Clan Modules:
- reference/clanModules/index.md
- reference/clanModules/admin.md
- reference/clanModules/borgbackup-static.md
- reference/clanModules/borgbackup.md
- reference/clanModules/deltachat.md
- reference/clanModules/dyndns.md
- reference/clanModules/disk-id.md
- reference/clanModules/dyndns.md
- reference/clanModules/ergochat.md
- reference/clanModules/garage.md
- reference/clanModules/golem-provider.md
- reference/clanModules/heisenbridge.md
- reference/clanModules/index.md
- reference/clanModules/iwd.md
- reference/clanModules/localbackup.md
- reference/clanModules/localsend.md
- reference/clanModules/matrix-synapse.md
- reference/clanModules/machine-id.md
- reference/clanModules/matrix-synapse.md
- reference/clanModules/moonlight.md
- reference/clanModules/mumble.md
- reference/clanModules/nginx.md
@@ -101,9 +102,11 @@ nav:
- reference/clanModules/vaultwarden.md
- reference/clanModules/xfce.md
- reference/clanModules/zerotier-static-peers.md
- reference/clanModules/zerotier.md
- reference/clanModules/zt-tcp-relay.md
- CLI:
- reference/cli/index.md
- reference/cli/backups.md
- reference/cli/facts.md
- reference/cli/flakes.md
@@ -117,6 +120,7 @@ nav:
- reference/cli/vms.md
- Clan Core:
- reference/clan-core/index.md
- reference/clan-core/backups.md
- reference/clan-core/facts.md
- reference/clan-core/sops.md

View File

@@ -65,10 +65,10 @@ def get_network_id() -> str:
def allow_member(args: argparse.Namespace) -> None:
member_id = args.member_id
if args.member_ip:
member_ip = args.member_id
member_id = compute_member_id(member_ip)
member_id = compute_member_id(args.member_id)
else:
member_id = args.member_id
network_id = get_network_id()
token = ZEROTIER_STATE_DIR.joinpath("authtoken.secret").read_text()
conn = http.client.HTTPConnection("localhost", 9993)