From 5f15ec44954ae6f73c9205532b549d59c30152e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= Date: Fri, 29 Sep 2023 10:51:38 +0200 Subject: [PATCH 1/3] add zerotier-members script --- nixosModules/clanCore/zerotier/default.nix | 7 ++ pkgs/flake-module.nix | 1 + pkgs/zerotier-members/default.nix | 14 ++++ pkgs/zerotier-members/zerotier-members.py | 78 ++++++++++++++++++++++ 4 files changed, 100 insertions(+) create mode 100644 pkgs/zerotier-members/default.nix create mode 100755 pkgs/zerotier-members/zerotier-members.py diff --git a/nixosModules/clanCore/zerotier/default.nix b/nixosModules/clanCore/zerotier/default.nix index 113fed6..fad719b 100644 --- a/nixosModules/clanCore/zerotier/default.nix +++ b/nixosModules/clanCore/zerotier/default.nix @@ -99,6 +99,8 @@ in ${pkgs.python3.interpreter} ${./generate-network.py} "$facts/zerotier-network-id" "$secrets/zerotier-identity-secret" ''; }; + environment.etc."zerotier/network-id".text = facts.zerotier-network-id.value; + environment.systemPackages = [ config.clanCore.clanPkgs.zerotier-members ]; }) (lib.mkIf ((config.clanCore.secrets ? zerotier) && (facts.zerotier-network-id.value != null)) { clan.networking.zerotier.networkId = facts.zerotier-network-id.value; @@ -109,6 +111,11 @@ in ln -sfT ${pkgs.writeText "net.json" (builtins.toJSON networkConfig)} /var/lib/zerotier-one/controller.d/network/${cfg.networkId}.json ''}" ]; + systemd.services.zerotierone.serviceConfig.ExecStartPost = [ + "+${pkgs.writeShellScript "whitelist-controller" '' + ${config.clanCore.clanPkgs.zerotier-members}/bin/zerotier-members allow ${builtins.substring 0 10 cfg.networkId} + ''}" + ]; }) ]; } diff --git a/pkgs/flake-module.nix b/pkgs/flake-module.nix index ede366f..52ff208 100644 --- a/pkgs/flake-module.nix +++ b/pkgs/flake-module.nix @@ -8,6 +8,7 @@ perSystem = { pkgs, config, ... }: { packages = { tea-create-pr = pkgs.callPackage ./tea-create-pr { }; + zerotier-members = pkgs.callPackage ./zerotier-members { }; merge-after-ci = pkgs.callPackage ./merge-after-ci { inherit (config.packages) tea-create-pr; }; diff --git a/pkgs/zerotier-members/default.nix b/pkgs/zerotier-members/default.nix new file mode 100644 index 0000000..450b079 --- /dev/null +++ b/pkgs/zerotier-members/default.nix @@ -0,0 +1,14 @@ +{ stdenv, python3, lib }: + +stdenv.mkDerivation { + name = "zerotier-members"; + src = ./.; + buildInputs = [ python3 ]; + installPhase = '' + install -Dm755 ${./zerotier-members.py} $out/bin/zerotier-members + ''; + meta = with lib; { + description = "A tool to list/allow members of a ZeroTier network"; + license = licenses.mit; + }; +} diff --git a/pkgs/zerotier-members/zerotier-members.py b/pkgs/zerotier-members/zerotier-members.py new file mode 100755 index 0000000..3bce0c1 --- /dev/null +++ b/pkgs/zerotier-members/zerotier-members.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python +import argparse +import http.client +import json +import sys +from pathlib import Path + +ZEROTIER_STATE_DIR = Path("/var/lib/zerotier-one") + + +class ClanError(Exception): + pass + + +# this is managed by the nixos module +def get_network_id() -> str: + p = Path("/etc/zerotier/network-id") + if not p.exists(): + raise ClanError( + f"{p} file not found. Have you enabled the zerotier controller on this host?" + ) + return p.read_text().strip() + + +def allow_member(args: argparse.Namespace) -> None: + 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) + conn.request( + "POST", + f"/controller/network/{network_id}/member/{member_id}", + '{"authorized": true}', + {"X-ZT1-AUTH": token}, + ) + resp = conn.getresponse() + if resp.status != 200: + raise ClanError( + f"the zerotier daemon returned this error: {resp.status} {resp.reason}" + ) + print(resp.status, resp.reason) + + +def list_members(args: argparse.Namespace) -> None: + network_id = get_network_id() + networks = ZEROTIER_STATE_DIR / "controller.d" / "network" / network_id / "member" + if not networks.exists(): + return + for member in networks.iterdir(): + with member.open() as f: + data = json.load(f) + try: + member_id = data["id"] + except KeyError: + raise ClanError(f"error: {member} does not contain an id") + print(member_id) + + +def main() -> None: + parser = argparse.ArgumentParser() + subparser = parser.add_subparsers(dest="command") + parser_allow = subparser.add_parser("allow", help="Allow a member to join") + parser_allow.add_argument("member_id") + parser_allow.set_defaults(func=allow_member) + + parser_list = subparser.add_parser("list", help="List members") + parser_list.set_defaults(func=list_members) + + args = parser.parse_args() + try: + args.func(args) + except ClanError as e: + print(e) + sys.exit(1) + + +if __name__ == "__main__": + main() From 9daeaf5c6213ef28514e90330227e197fb8262ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= Date: Fri, 29 Sep 2023 16:04:56 +0200 Subject: [PATCH 2/3] zerotier: fix creating controller directory --- nixosModules/clanCore/zerotier/default.nix | 1 + pyproject.toml | 35 ++++++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 pyproject.toml diff --git a/nixosModules/clanCore/zerotier/default.nix b/nixosModules/clanCore/zerotier/default.nix index fad719b..439f921 100644 --- a/nixosModules/clanCore/zerotier/default.nix +++ b/nixosModules/clanCore/zerotier/default.nix @@ -108,6 +108,7 @@ in systemd.services.zerotierone.serviceConfig.ExecStartPre = [ "+${pkgs.writeShellScript "init-zerotier" '' cp ${config.clanCore.secrets.zerotier.secrets.zerotier-identity-secret.path} /var/lib/zerotier-one/identity.secret + mkdir -p /var/lib/zerotier-one/controller.d/network ln -sfT ${pkgs.writeText "net.json" (builtins.toJSON networkConfig)} /var/lib/zerotier-one/controller.d/network/${cfg.networkId}.json ''}" ]; diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..4c77b28 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,35 @@ +[tool.mypy] +python_version = "3.10" +warn_redundant_casts = true +disallow_untyped_calls = true +disallow_untyped_defs = true +no_implicit_optional = true +exclude = "clan_cli.nixpkgs" + +[tool.ruff] +line-length = 88 + +select = [ "E", "F", "I", "U", "N"] +ignore = [ "E501" ] + +[tool.black] +line-length = 88 +target-version = [ "py310" ] +include = "\\.pyi?$" +exclude = ''' +/( + \.git + | \.hg + | \.mypy_cache + | \.tox + | \.venv + | _build + | buck-out + | build + | dist + # The following are specific to Black, you probably don't want those. + | blib2to3 + | tests/data + | profiling +)/ +''' From 89e69e5cb6262d702fe61dafb1c346374c182c88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= Date: Fri, 29 Sep 2023 16:41:14 +0200 Subject: [PATCH 3/3] add treewide pyproject.toml Than we don't need a pyproject.toml per script --- nixosModules/clanCore/zerotier/pyproject.toml | 35 ------------------- 1 file changed, 35 deletions(-) delete mode 100644 nixosModules/clanCore/zerotier/pyproject.toml diff --git a/nixosModules/clanCore/zerotier/pyproject.toml b/nixosModules/clanCore/zerotier/pyproject.toml deleted file mode 100644 index 4c77b28..0000000 --- a/nixosModules/clanCore/zerotier/pyproject.toml +++ /dev/null @@ -1,35 +0,0 @@ -[tool.mypy] -python_version = "3.10" -warn_redundant_casts = true -disallow_untyped_calls = true -disallow_untyped_defs = true -no_implicit_optional = true -exclude = "clan_cli.nixpkgs" - -[tool.ruff] -line-length = 88 - -select = [ "E", "F", "I", "U", "N"] -ignore = [ "E501" ] - -[tool.black] -line-length = 88 -target-version = [ "py310" ] -include = "\\.pyi?$" -exclude = ''' -/( - \.git - | \.hg - | \.mypy_cache - | \.tox - | \.venv - | _build - | buck-out - | build - | dist - # The following are specific to Black, you probably don't want those. - | blib2to3 - | tests/data - | profiling -)/ -'''