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