From eab11d4a5b96e820f7ed5b6ad22e9c9a586c66f1 Mon Sep 17 00:00:00 2001 From: lilly Date: Fri, 21 Feb 2025 21:15:20 +0100 Subject: [PATCH 1/2] add script to fetch netbox data and write to local files --- data/zones/noc.eh22.intern.zone | 6 ++ flake.nix | 6 ++ packages/default.nix | 1 + packages/fetch-netbox-data/default.nix | 23 ++++++++ .../fetch-netbox-data/fetch-netbox-data.py | 55 +++++++++++++++++++ secrets/passwords.yaml | 7 ++- 6 files changed, 96 insertions(+), 2 deletions(-) create mode 100644 data/zones/noc.eh22.intern.zone create mode 100644 packages/fetch-netbox-data/default.nix create mode 100755 packages/fetch-netbox-data/fetch-netbox-data.py diff --git a/data/zones/noc.eh22.intern.zone b/data/zones/noc.eh22.intern.zone new file mode 100644 index 0000000..1f6a657 --- /dev/null +++ b/data/zones/noc.eh22.intern.zone @@ -0,0 +1,6 @@ +$ORIGIN noc.eh22.intern. +@ 0 IN SOA auth-dns noc.eh22.easterhegg.eu. 1 7200 3600 3600000 60 +@ 0 IN NS 10.20.25.3. +auth-dns 0 IN A 10.20.25.3 +proxmox 0 IN A 10.20.25.1 +sketchy-router 0 IN A 10.20.25.2 diff --git a/flake.nix b/flake.nix index 766d326..3caf6a3 100644 --- a/flake.nix +++ b/flake.nix @@ -84,6 +84,12 @@ ssh-to-age pre-commit sops + python312 + python312Packages.pynetbox + python312Packages.dnspython + python312Packages.ipython + # custom packages + fetch-netbox-data ]; }; }); diff --git a/packages/default.nix b/packages/default.nix index 5917dfe..0df9bed 100644 --- a/packages/default.nix +++ b/packages/default.nix @@ -2,5 +2,6 @@ { # add new packages here as: # name = pkgs.callPackage ./package-source.nix {}; + fetch-netbox-data = pkgs.callPackage ./fetch-netbox-data { }; installer = flake.outputs.nixosConfigurations.installer.config.system.build.isoImage; } diff --git a/packages/fetch-netbox-data/default.nix b/packages/fetch-netbox-data/default.nix new file mode 100644 index 0000000..7ac6b3a --- /dev/null +++ b/packages/fetch-netbox-data/default.nix @@ -0,0 +1,23 @@ +{ python3 }: +python3.pkgs.buildPythonApplication { + name = "fetch-netbox-data"; + version = "1.0.0"; + src = ./.; + pyproject = false; + + propagatedBuildInputs = with python3.pkgs; [ + pynetbox + dnspython + ]; + + installPhase = '' + runHook preInstall + install -Dm755 ./fetch-netbox-data.py $out/bin/fetch-netbox-data + runHook postInstall + ''; + + meta = { + mainProgram = "fetch-netbox-data"; + platforms = python3.meta.platforms; + }; +} diff --git a/packages/fetch-netbox-data/fetch-netbox-data.py b/packages/fetch-netbox-data/fetch-netbox-data.py new file mode 100755 index 0000000..3ff99e3 --- /dev/null +++ b/packages/fetch-netbox-data/fetch-netbox-data.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python3 +import pynetbox +import argparse +from dns import rdatatype +from dns import rdataclass +from dns.rdtypes.ANY.SOA import SOA +from dns.rdtypes.ANY.NS import NS +from dns.rdtypes.IN.A import A +from dns.zone import Zone +from pathlib import Path + + +def build_auth_dns_zones(nb: pynetbox.api, nox_dir: Path): + zones_dir = nox_dir / "data" / "zones" + zones_dir.mkdir(parents=True,exist_ok=True) + print(f"Fetching IPAM data to build authorative zonefiles in {zones_dir}") + + print(f"Building zone noc.eh22.intern") + zonefile_path = zones_dir / "noc.eh22.intern.zone" + + # build zone management stuff (SOA record, NS record) + zone = Zone(origin="noc.eh22.intern") + zone.get_rdataset("@", rdtype=rdatatype.SOA, create=True)\ + .add(SOA(rdclass=rdataclass.IN, rdtype=rdatatype.SOA, mname="auth-dns.noc.eh22.intern.", rname="noc.eh22.easterhegg.eu.", serial=1, refresh=7200, retry=3600, expire=3600000, minimum=60)) + zone.get_rdataset("@", rdtype=rdatatype.NS, create=True)\ + .add(NS(rdclass=rdataclass.IN, rdtype=rdatatype.NS, target="10.20.25.3")) + + # iterate over all ip addresses with dns names ending in noc.eh22.intern + for i_addr in nb.ipam.ip_addresses.filter("noc.eh22.intern"): + raw_addr = i_addr.address.rsplit("/", maxsplit=1)[0] + relative_name = i_addr.dns_name.removesuffix(".noc.eh22.intern") + if i_addr.family.value == 4: + zone.get_rdataset(relative_name, rdtype=rdatatype.A, create=True)\ + .add(A(rdclass=rdataclass.IN, rdtype=rdatatype.A, address=raw_addr)) + else: + raise RuntimeError(f"Got unknown IP family {i_addr.family} ({i_addr.family.value})") + + with open(zonefile_path, mode="w") as f: + zone.to_file(f, want_comments=True, want_origin=True) + + +def main(): + argp = argparse.ArgumentParser(prog="fetch-netbox-data", description="Fetch current IPAM data from netbox") + argp.add_argument("--base-url", default="https://netbox.eh22.easterhegg.eu", help="URL of the netbox installation") + argp.add_argument("--token", required=True, help="Netbox API Token") + argp.add_argument("--nox-dir", required=True, type=Path, help="Path to the nox repository") + args = argp.parse_args() + + nb = pynetbox.api(args.base_url, token=args.token) + build_auth_dns_zones(nb, args.nox_dir) + + + +if __name__ == "__main__": + main() diff --git a/secrets/passwords.yaml b/secrets/passwords.yaml index baf6b24..8806649 100644 --- a/secrets/passwords.yaml +++ b/secrets/passwords.yaml @@ -1,4 +1,7 @@ services: + netbox.eh22.easterhegg.eu: + noc: ENC[AES256_GCM,data:OX05HjLYVoMP4My97eijGjWDl+lyTBFa,iv:EDOWfkNZUrFFyrX63LhA4O8lqfmckOHcXRN0qzgn3u4=,tag:AwrwlwGoKih2qkbvmQIGFQ==,type:str] + noc_token: ENC[AES256_GCM,data:7WrIXDtjYKRVgA+r2iVcaT4zf+ftRTEQDEduu77j3RkvSX1e2UCNvg==,iv:B1r+wHg3AJKVj7PKS34G9FD/2Q1yngXdueqVJ0JIfY0=,tag:1w9FO2fPPK0gkInrtEZyBg==,type:str] proxmox: root: ENC[AES256_GCM,data:RVv1d/nB9pgcERkujSasoLY+cR3OO3NWxw==,iv:EHkUDxP6XB2JWeDtno2rcVvBQdJ/jmG5HjRjPppfS0A=,tag:obzij0BkGLJoXfUbqWLRjw==,type:str] hardware: @@ -24,8 +27,8 @@ sops: Q0ZGUFBmUWpUYjR5OUwxOUplblZ0SmcKtMl1KoYwPb776zz8FfFnf0s7XlnOLnuU nXkPxRaDel/3EsLnfhcONRAKTGdleRHAXQVIGHrs/jjnZ2OJgXIzYA== -----END AGE ENCRYPTED FILE----- - lastmodified: "2025-02-10T16:13:13Z" - mac: ENC[AES256_GCM,data:k7lqf+JNpnmbKYjMuu82Q1DPtYsL7jAfwUh8QEjpyq9+Qael1dyV0e1yn/H1prLuZIbebT1rYX6s/MhT3t7Ts88bQHmf/EDyCeOPnRfRctzY1jQPPKbE3Pe7vtEnx5r/DEksi1Jh8vMoqHYcB987WPjAQn27P58UXYJROpqaSwg=,iv:fT9JnWYs8lEjXL3pXHtERRxccGd/ocb6KCc8gGbpBJg=,tag:rMvQoihg53GSNhYiNtypuQ==,type:str] + lastmodified: "2025-02-21T18:34:34Z" + mac: ENC[AES256_GCM,data:yeMXclT2ZdxHy2CqWQkXVay4EHHq2o8dXF2yXa7q1FKyteRzf0Gve/IQVxH3VXYsGQf3lSdL5EAe3BXmNesWnA5QfTELt2hzgd5nQ6+NTzLDXmi/AW3L4BhzpOoK7UIJ+mG42N4mkYlBe1dUyDBikxevWB3AAzGl7mAF/2io4TQ=,iv:d4g5dWUhFBauR8+4aPGU1hYkhyGsmdGBjgwBMs0HbtA=,tag:oOYKKCwOw/gjqeB/SCdkuQ==,type:str] pgp: [] unencrypted_suffix: _unencrypted version: 3.9.4 From d31677b549307770cc21231a44ab2125f85da79d Mon Sep 17 00:00:00 2001 From: lilly Date: Fri, 21 Feb 2025 21:15:48 +0100 Subject: [PATCH 2/2] configure auth-dns to use netbox-fetched data --- systems/auth-dns.noc.eh22.intern.nix | 35 ++++++++++------------ systems/sketchy-router.noc.eh22.intern.nix | 6 ++++ 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/systems/auth-dns.noc.eh22.intern.nix b/systems/auth-dns.noc.eh22.intern.nix index 1b83f39..1ccfcb2 100644 --- a/systems/auth-dns.noc.eh22.intern.nix +++ b/systems/auth-dns.noc.eh22.intern.nix @@ -1,26 +1,15 @@ { pkgs, + lib, ... }: let - noc_eh22_internZone = '' - $ORIGIN noc.eh22.intern. - $TTL 3600 - - ; zone management - noc.eh22.intern. IN SOA auth-dns.noc.eh22.intern. noc.eh22.esterhegg.eu. ( - 1 ; serial (automatically incremented by knot) - 7200 ; refresh - 3600 ; retry - 3600000 ; expire - 60 ; negative response caching ttl - ) - @ IN NS auth-dns - - ; A/AAAA records - proxmox IN A 10.31.210.248 - auth-dns IN A 10.31.210.253 - ''; + zones = ( + lib.attrsets.mapAttrs' (name: fileType: { + name = name; + value = ../data/zones/${name}; + }) (builtins.readDir ../data/zones) + ); knotConf = pkgs.writeText "knot.conf" '' server: @@ -48,7 +37,15 @@ in # enable knot authorative dns server # ref: https://search.nüschtos.de/?query=services.knot # https://www.knot-dns.cz/docs/3.4/html/configuration.html - environment.etc."knot/zones/noc.eh22.intern.zone".text = noc_eh22_internZone; + environment.etc = ( + lib.attrsets.mapAttrs' (name: value: { + name = "knot/zones/noc.eh22.intern.zone"; + value = { + source = value; + }; + }) zones + ); + services.knot = { enable = true; settingsFile = knotConf; diff --git a/systems/sketchy-router.noc.eh22.intern.nix b/systems/sketchy-router.noc.eh22.intern.nix index 3617e67..feeba88 100644 --- a/systems/sketchy-router.noc.eh22.intern.nix +++ b/systems/sketchy-router.noc.eh22.intern.nix @@ -69,6 +69,12 @@ id = 300; subnet = "10.20.25.0/24"; pools = [ { pool = "10.20.25.100 - 10.20.25.254"; } ]; + reservations = [ + { + hw-address = "bc:24:11:c1:8a:a4"; + ip-address = "10.20.25.3"; + } + ]; } ]; }