Compare commits
1 Commits
9a05d2a072
...
zerotier_r
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1b3f087079 |
@@ -6,94 +6,74 @@
|
||||
manifest.categories = [ "Utility" ];
|
||||
manifest.readme = builtins.readFile ./README.md;
|
||||
|
||||
roles.peer = {
|
||||
perInstance =
|
||||
{
|
||||
instanceName,
|
||||
roles,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
{
|
||||
exports.networking = {
|
||||
priority = lib.mkDefault 900;
|
||||
# TODO add user space network support to clan-cli
|
||||
module = "clan_lib.network.zerotier";
|
||||
peers = lib.mapAttrs (name: _machine: {
|
||||
host.var = {
|
||||
machine = name;
|
||||
generator = "zerotier";
|
||||
file = "zerotier-ip";
|
||||
};
|
||||
}) roles.peer.machines;
|
||||
};
|
||||
nixosModule =
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
{
|
||||
imports = [
|
||||
(import ./shared.nix {
|
||||
inherit
|
||||
instanceName
|
||||
roles
|
||||
config
|
||||
lib
|
||||
pkgs
|
||||
;
|
||||
})
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
roles.moon = {
|
||||
roles.default = {
|
||||
interface =
|
||||
{ lib, ... }:
|
||||
{
|
||||
options.stableEndpoints = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
options.networkId = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.str;
|
||||
default = null;
|
||||
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.
|
||||
'';
|
||||
example = ''
|
||||
[ "1.2.3.4" "10.0.0.3/9993" "2001:abcd:abcd::3/9993" ]
|
||||
The zerotier network id to use. If not set, a network will be generated for you.
|
||||
If you administrate your zerotier network via my.zerotier.com, you should set this.
|
||||
'';
|
||||
example = "8056c2e21c000001";
|
||||
};
|
||||
|
||||
};
|
||||
perInstance =
|
||||
{
|
||||
instanceName,
|
||||
settings,
|
||||
roles,
|
||||
...
|
||||
}:
|
||||
{ instanceName, settings, ... }:
|
||||
{
|
||||
nixosModule =
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
{
|
||||
config.clan.core.networking.zerotier.moon.stableEndpoints = settings.stableEndpoints;
|
||||
config = lib.mkMerge [
|
||||
# code to start/configure zerotier
|
||||
({ config, ... }: {
|
||||
services.zerotierone = {
|
||||
enable = true;
|
||||
joinNetworks = [ config.clan."zerotier_${instanceName}".networkId ];
|
||||
};
|
||||
systemd.network.networks."09-zerotier" = {
|
||||
matchConfig.Name = "zt*";
|
||||
networkConfig = {
|
||||
LLDP = true;
|
||||
MulticastDNS = true;
|
||||
KeepConfiguration = "static";
|
||||
};
|
||||
};
|
||||
|
||||
imports = [
|
||||
(import ./shared.nix {
|
||||
inherit
|
||||
instanceName
|
||||
roles
|
||||
config
|
||||
lib
|
||||
pkgs
|
||||
;
|
||||
systemd.services.zerotierone.serviceConfig.ExecStartPre = [
|
||||
"+${pkgs.writeShellScript "init-zerotier" ''
|
||||
# compare hashes of the current identity secret and the one in the config
|
||||
hash1=$(sha256sum /var/lib/zerotier-one/identity.secret | cut -d ' ' -f 1)
|
||||
hash2=$(sha256sum ${config.clan.core.vars.generators.zerotier.files.zerotier-identity-secret.path} | cut -d ' ' -f 1)
|
||||
if [[ "$hash1" != "$hash2" ]]; then
|
||||
echo "Identity secret has changed, backing up old identity to /var/lib/zerotier-one/identity.secret.bac"
|
||||
cp /var/lib/zerotier-one/identity.secret /var/lib/zerotier-one/identity.secret.bac
|
||||
cp /var/lib/zerotier-one/identity.public /var/lib/zerotier-one/identity.public.bac
|
||||
cp ${config.clan.core.vars.generators.zerotier.files.zerotier-identity-secret.path} /var/lib/zerotier-one/identity.secret
|
||||
zerotier-idtool getpublic /var/lib/zerotier-one/identity.secret > /var/lib/zerotier-one/identity.public
|
||||
fi
|
||||
|
||||
# cleanup old networks
|
||||
if [[ -d /var/lib/zerotier-one/networks.d ]]; then
|
||||
find /var/lib/zerotier-one/networks.d \
|
||||
-type f \
|
||||
-name "*.conf" \
|
||||
-not \( ${
|
||||
lib.concatMapStringsSep " -o " (
|
||||
netId: ''-name "${netId}.conf"''
|
||||
) config.services.zerotierone.joinNetworks
|
||||
} \) \
|
||||
-delete
|
||||
fi
|
||||
''}"
|
||||
];
|
||||
})
|
||||
];
|
||||
};
|
||||
@@ -104,7 +84,8 @@
|
||||
interface =
|
||||
{ lib, ... }:
|
||||
{
|
||||
options.allowedIps = lib.mkOption {
|
||||
options = {
|
||||
allowedIps = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ ];
|
||||
description = ''
|
||||
@@ -115,6 +96,11 @@
|
||||
[ "fd5d:bbe3:cbc5:fe6b:f699:935d:bbe3:cbc5" ]
|
||||
'';
|
||||
};
|
||||
settings = lib.mkOption {
|
||||
description = "override the network config in /var/lib/zerotier/bla/$network.json";
|
||||
type = lib.types.json;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
perInstance =
|
||||
@@ -136,18 +122,20 @@
|
||||
uniqueStrings = list: builtins.attrNames (builtins.groupBy lib.id list);
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
(import ./shared.nix {
|
||||
inherit
|
||||
instanceName
|
||||
roles
|
||||
config
|
||||
lib
|
||||
pkgs
|
||||
;
|
||||
})
|
||||
systemd.services.zerotierone.serviceConfig.ExecStartPre = [
|
||||
"+${pkgs.writeShellScript "init-zerotier-${instanceName}" ''
|
||||
mkdir -p /var/lib/zerotier-one/controller.d/${instanceName}
|
||||
ln -sfT ${pkgs.writeText "net.json" (builtins.toJSON settings.settings)} /var/lib/zerotier-one/controller.d/network/${config.clan."zerotier_${instanceName}".networkId}.json
|
||||
|
||||
''}"
|
||||
];
|
||||
systemd.services.zerotierone.serviceConfig.ExecStartPost = [
|
||||
"+${pkgs.writeShellScript "whitelist-controller" ''
|
||||
${config.clan.core.clanPkgs.zerotier-members}/bin/zerotier-members allow ${
|
||||
builtins.substring 0 10 config.clan."zerotier_${instanceName}".networkId
|
||||
}
|
||||
''}"
|
||||
];
|
||||
config = {
|
||||
systemd.services.zerotier-inventory-autoaccept =
|
||||
let
|
||||
machines = uniqueStrings (
|
||||
@@ -180,9 +168,88 @@
|
||||
'';
|
||||
};
|
||||
|
||||
clan.core.networking.zerotier.controller.enable = lib.mkDefault true;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# there a bunch of different scenarios that can happen which we need to take care of
|
||||
## controller is not a peer (the controller doesn't have an ipv4 and is not part of the network)
|
||||
## controller has multiple networks (currently the code only creates a single network per controller, so we need to figure out the API call to get another network created)
|
||||
## controller has multiple networks but is peer in only some
|
||||
## I guess we need to make an attrset of controllers to networks and then create the networks with the controller key
|
||||
# every controller key will be shared, so all network specific ids can be shared
|
||||
perMachine = { instances, machine, lib, ... }: let
|
||||
# an attrset of { controller1 = { instance1 = {}; instance2 = {}; }; controller2 = { instance3 = {}; }; }
|
||||
controllerNetworks = lib.foldlAttrs (acc: instanceName: instance: lib.recursiveUpdate acc { ${lib.head (lib.attrNames instance.roles.controller.machines)} = { ${instanceName} = {}; }; }) {} instances;
|
||||
getInstanceController = instance: lib.head (lib.attrNames instance.roles.controller.machines);
|
||||
in {
|
||||
nixosModule = { pkgs, config, ... }: {
|
||||
config = lib.mkMerge [
|
||||
{ # every controller gets a shared network key, from which we can derive multiple network ids
|
||||
# we have this var shared, so we can create it when evaluating any machine
|
||||
clan.core.vars.generators = lib.mapAttrs' (controllerName: _: lib.nameValuePair "zerotier_controller_${controllerName}" {
|
||||
shared = true;
|
||||
files.zerotier-identity-secret.deploy = false;
|
||||
runtimeInputs = [
|
||||
config.services.zerotierone.package
|
||||
pkgs.python3
|
||||
];
|
||||
script = ''
|
||||
python3 ${./generate.py} --mode network \
|
||||
--ip "$out/zerotier-ip" \
|
||||
--identity-secret "$out/zerotier-identity-secret"
|
||||
'';
|
||||
}) controllerNetworks;
|
||||
}
|
||||
{ # every instance in a controller gets a network id, which is derived from the controller's shared network key
|
||||
clan.core.vars.generators = lib.mapAttrs' (instanceName: instance: lib.nameValuePair "zerotier_network_${instanceName}" {
|
||||
shared = true;
|
||||
files.zerotier-network-id.secret = false;
|
||||
dependencies = [
|
||||
config.clan.core.vars.generators."zerotier_controller_${getInstanceController instance}"
|
||||
];
|
||||
runtimeInputs = [
|
||||
config.services.zerotierone.package
|
||||
pkgs.python3
|
||||
];
|
||||
script = ''
|
||||
python3 ${./generate.py} --mode network-id \
|
||||
--network-id "$out/zerotier-network-id"
|
||||
# TODO we need to pass in the controller key
|
||||
'';
|
||||
}) instances;
|
||||
}
|
||||
{ # define nixos options, which we need to propagate certain information to other roles (like controller)
|
||||
options.clan = lib.mapAttrs' (instanceName: _: lib.nameValuePair "zerotier_${instanceName}" {
|
||||
networkId = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "The zerotier network id assigned to this machine";
|
||||
default = if instances.${instanceName}.settings.networkId != null then instances.${instanceName}.settings.networkId else "generated-per-machine";
|
||||
};
|
||||
});
|
||||
}
|
||||
# if we have set null as networkId, we assume that we have a controller and generate a shared key for it
|
||||
# (lib.mkIf (settings.networkId == null) {
|
||||
# clan.core.vars.generators."zerotier_${instanceName}" = {
|
||||
# files.zerotier-network-id.secret = false;
|
||||
# files.zerotier-identity-secret.deploy = false;
|
||||
# shared = true;
|
||||
# runtimeInputs = [
|
||||
# config.services.zerotierone.package
|
||||
# pkgs.python3
|
||||
# ];
|
||||
# script = ''
|
||||
# source ${(pkgs.callPackage ../../../pkgs/minifakeroot { })}/share/minifakeroot/rc
|
||||
# python3 ${./generate.py} --mode network \
|
||||
# --ip "$out/zerotier-ip" \
|
||||
# --identity-secret "$out/zerotier-identity-secret" \
|
||||
# --network-id "$out/zerotier-network-id"
|
||||
# '';
|
||||
# };
|
||||
# clan."zerotier_${instanceName}".networkId =
|
||||
# config.clan.core.vars.generators."zerotier_${instanceName}".files.zerotier-network-id.value;
|
||||
# })
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -28,38 +28,5 @@ in
|
||||
config = {
|
||||
clan.core.networking.zerotier.networkId = networkId;
|
||||
clan.core.networking.zerotier.name = instanceName;
|
||||
|
||||
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()
|
||||
''}"
|
||||
]
|
||||
);
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user