From fd36e012f93d36c463f9b86b8e48dbd28e4a6866 Mon Sep 17 00:00:00 2001 From: prescientmoon Date: Mon, 8 Jul 2024 03:06:27 +0200 Subject: [PATCH] Custom octodns setup! --- dns/common.nix | 74 +++++++++++++++++++ dns/octodns.yaml | 20 +++++ dns/pkgs.nix | 37 ++++++++++ flake.nix | 7 +- home/features/wayland/hyprland/hyprland.conf | 2 +- hosts/nixos/common/global/default.nix | 3 + hosts/nixos/common/global/ports.nix | 1 + .../nixos/common/optional/services/nginx.nix | 1 - .../common/optional/services/syncthing.nix | 7 ++ hosts/nixos/common/secrets.yaml | 6 +- hosts/nixos/lapetus/default.nix | 18 ++++- hosts/nixos/lapetus/services/forgejo.nix | 17 ++--- hosts/nixos/lapetus/services/homer.nix | 2 +- hosts/nixos/lapetus/services/jupyter.nix | 4 +- hosts/nixos/lapetus/services/microbin.nix | 10 +-- hosts/nixos/lapetus/services/pounce.nix | 17 ++++- hosts/nixos/lapetus/services/syncthing.nix | 12 --- hosts/nixos/tethys/default.nix | 16 +++- modules/common/octodns.nix | 46 ++++++++++++ modules/nixos/cloudflared.nix | 39 +++++++++- modules/nixos/default.nix | 2 + modules/nixos/dns-assertions.nix | 17 +++++ modules/nixos/dns.nix | 59 +++++++++++++++ modules/nixos/nginx.nix | 27 +++++-- pkgs/default.nix | 2 +- pkgs/octodns-cloudflare.nix | 45 +++++++++++ scripts/dns/dns.txt | 2 +- 27 files changed, 434 insertions(+), 59 deletions(-) create mode 100644 dns/common.nix create mode 100644 dns/octodns.yaml create mode 100644 dns/pkgs.nix delete mode 100644 hosts/nixos/lapetus/services/syncthing.nix create mode 100644 modules/common/octodns.nix create mode 100644 modules/nixos/dns-assertions.nix create mode 100644 modules/nixos/dns.nix create mode 100644 pkgs/octodns-cloudflare.nix diff --git a/dns/common.nix b/dns/common.nix new file mode 100644 index 0000000..39e0ebe --- /dev/null +++ b/dns/common.nix @@ -0,0 +1,74 @@ +# DNS entries which do not belong to a particular host +{ lib, ... }: +let + # {{{ Github pages helper + ghPage = at: [{ + inherit at; type = "CNAME"; + value = "prescientmoon.github.io."; + }]; + # }}} + # {{{ Migadu mail DNS setup + migaduMail = at: verifyKey: + let atPrefix = prefix: if at == "" then prefix else "${prefix}.${at}"; + in + [ + { + inherit at; + ttl = 600; + type = "MX"; + value = [ + { + exchange = "aspmx1.migadu.com."; + preference = 10; + } + { + exchange = "aspmx2.migadu.com."; + preference = 20; + } + ]; + } + { + inherit at; + ttl = 600; + type = "TXT"; + value = [ + "v=spf1 include:spf.migadu.com -all" + "hosted-email-verify=${verifyKey}" + ]; + } + { + at = atPrefix "_dmarc"; + type = "TXT"; + value = ''v=DMARC1\; p=quarantine\;''; + ttl = 600; + } + { + at = atPrefix "key1._domainkey"; + type = "CNAME"; + value = "key1.orbit.moonythm.dev._domainkey.migadu.com."; + ttl = 600; + } + { + at = atPrefix "key2._domainkey"; + type = "CNAME"; + value = "key2.orbit.moonythm.dev._domainkey.migadu.com."; + ttl = 600; + } + { + at = atPrefix "key3._domainkey"; + type = "CNAME"; + value = "key3.orbit.moonythm.dev._domainkey.migadu.com."; + ttl = 600; + } + ]; + # }}} +in +{ + satellite.dns.domain = "moonythm.dev"; + satellite.dns.records = lib.flatten [ + (ghPage "doffycup") + (ghPage "erratic-gate") + (migaduMail "" "kfkhyexd") + (migaduMail "orbit" "24s7lnum") + ]; +} diff --git a/dns/octodns.yaml b/dns/octodns.yaml new file mode 100644 index 0000000..9734776 --- /dev/null +++ b/dns/octodns.yaml @@ -0,0 +1,20 @@ +manager: + max_workers: 10 + +providers: + zones: + class: octodns.provider.yaml.YamlProvider + default_ttl: 300 + enforce_order: true + directory: this is set by nix :3 + + cloudflare: + class: octodns_cloudflare.CloudflareProvider + token: 'env/CLOUDFLARE_TOKEN' + +zones: + moonythm.dev.: + sources: + - zones + targets: + - cloudflare diff --git a/dns/pkgs.nix b/dns/pkgs.nix new file mode 100644 index 0000000..3773b1a --- /dev/null +++ b/dns/pkgs.nix @@ -0,0 +1,37 @@ +{ pkgs, self, system, ... }: rec { + octodns-zones = + let + nixosConfigModules = pkgs.lib.mapAttrsToList + (_: current: { satellite.dns = current.config.satellite.dns; }) + self.nixosConfigurations; + + evaluated = pkgs.lib.evalModules { + specialArgs = { inherit pkgs; }; + modules = [ + ../modules/nixos/dns.nix + ../modules/common/octodns.nix + ./common.nix + ] + ++ nixosConfigModules; + }; + in + evaluated.config.satellite.dns.octodns; + octodns-sync = + pkgs.symlinkJoin { + name = "octodns-sync"; + paths = [ self.packages.${system}.octodns ]; + buildInputs = [ pkgs.makeWrapper pkgs.yq ]; + postBuild = '' + cat ${./octodns.yaml} | yq '.providers.zones.directory="${octodns-zones}"' > $out/config.yaml + wrapProgram $out/bin/octodns-sync \ + --run 'export CLOUDFLARE_TOKEN=$( \ + sops \ + --decrypt \ + --extract "[\"cloudflare_dns_api_token\"]" \ + ./hosts/nixos/common/secrets.yaml \ + )' \ + --add-flags "--config-file $out/config.yaml" + ''; + }; +} + diff --git a/flake.nix b/flake.nix index 76017af..ed55489 100644 --- a/flake.nix +++ b/flake.nix @@ -106,11 +106,12 @@ let pkgs = nixpkgs.legacyPackages.${system}; upkgs = inputs.nixpkgs-unstable.legacyPackages.${system}; + myPkgs = import ./pkgs { inherit pkgs upkgs; }; in - import ./pkgs { inherit pkgs upkgs; } // { + myPkgs // { octodns = upkgs.octodns.withProviders - (ps: [ (import ./pkgs { inherit pkgs upkgs; }).octodns-cloudflare ]); - } + (ps: [ myPkgs.octodns-cloudflare ]); + } // (import ./dns/pkgs.nix) { inherit pkgs self system; } ); # }}} # {{{ Bootstrapping and other pinned devshells diff --git a/home/features/wayland/hyprland/hyprland.conf b/home/features/wayland/hyprland/hyprland.conf index 915a275..9a1b4c2 100644 --- a/home/features/wayland/hyprland/hyprland.conf +++ b/home/features/wayland/hyprland/hyprland.conf @@ -44,7 +44,7 @@ animations { } # Execute apps at launch -exec-once = wezterm & firefox & discocss & spot & obsidian & obsidiantui & smosgui +exec-once = wezterm & firefox & discocss & spotify & obsidiantui & smostui # Without this, xdg-open doesn't work exec = systemctl --user import-environment PATH && systemctl --user restart xdg-desktop-portal.service diff --git a/hosts/nixos/common/global/default.nix b/hosts/nixos/common/global/default.nix index 0934727..18abaa5 100644 --- a/hosts/nixos/common/global/default.nix +++ b/hosts/nixos/common/global/default.nix @@ -54,4 +54,7 @@ in config.allowUnfree = true; }; + + # Root domain used throughout my config + satellite.dns.domain = "moonythm.dev"; } diff --git a/hosts/nixos/common/global/ports.nix b/hosts/nixos/common/global/ports.nix index b94489b..f16797b 100644 --- a/hosts/nixos/common/global/ports.nix +++ b/hosts/nixos/common/global/ports.nix @@ -23,5 +23,6 @@ forgejo = 8419; jupyterhub = 8420; guacamole = 8421; + syncthing = 8422; }; } diff --git a/hosts/nixos/common/optional/services/nginx.nix b/hosts/nixos/common/optional/services/nginx.nix index 723a441..3e6b801 100644 --- a/hosts/nixos/common/optional/services/nginx.nix +++ b/hosts/nixos/common/optional/services/nginx.nix @@ -1,6 +1,5 @@ { imports = [ ./acme.nix ]; - satellite.nginx.domain = "moonythm.dev"; # Root domain used throughout my config services.nginx = { enable = true; recommendedGzipSettings = true; diff --git a/hosts/nixos/common/optional/services/syncthing.nix b/hosts/nixos/common/optional/services/syncthing.nix index 8e0a191..ba4c1eb 100644 --- a/hosts/nixos/common/optional/services/syncthing.nix +++ b/hosts/nixos/common/optional/services/syncthing.nix @@ -28,8 +28,15 @@ in extraOptions.options.crashReportingEnabled = false; }; + + guiAddress = "127.0.0.1:${toString config.satellite.ports.syncthing}"; + settings.gui.insecureSkipHostcheck = true; }; + # Expose gui interface via nginx + satellite.nginx.at."syncthing.${config.networking.hostName}".port = + config.satellite.ports.syncthing; + # Syncthing seems to leak memory, so we want to restart it daily. systemd.services.syncthing.serviceConfig.RuntimeMaxSec = "1d"; diff --git a/hosts/nixos/common/secrets.yaml b/hosts/nixos/common/secrets.yaml index 291e79a..2d9d7dd 100644 --- a/hosts/nixos/common/secrets.yaml +++ b/hosts/nixos/common/secrets.yaml @@ -1,6 +1,6 @@ wireless: ENC[AES256_GCM,data:Ib0PdBd2r/DPyE6Ah9NffT8Tw8c2y+seGFrE0e9GkyRaStdYMiiIlWCiaBO0u1HHaVV+2MQ33MnMdqyCGRlqGk45kl0GIwVR5iAiSYnobj/6wcse+kx/+5mzNOHXD1kJRGJBm5+SN9ntiGABNkQXJdn/Qoc/ukY1uaGe2nBeFKmGdD9JL7KfgdI5jYjQYyDbCL9JUszxkXNcplIRBAAy8JDaBVeo9HgI0QDIZToPKwuEeQoA9XzdimrjbCazlZy3ZvjAuoQXmrc1nIRHF5GabSRGTFTnTfcBeW2fGpUxmIhLyucn2DIQBXLm+RDdMLWoqcGbKiLVqKyUXck3ZZyoHMf2b9N52xMUwcS7,iv:ozkDwWmurWTD8TZHGvWL9Yh8cOrP1PzSBkz+1bBZybo=,tag:iGPjRaOoGRcOWJMweTL2yA==,type:str] pilot_password: ENC[AES256_GCM,data:PiKJCv5x68O9HFM4UvqLnsSPtqFslBLeAg67OkvFAbw7WaqbXh/p5SQblhPHcJ7jQDc4kI3XesOxruZrfJ0aZNDV1g7MWecgKg==,iv:EVs/m83Zfx2NRQMO52cF6pCe1ETpYfaR6lmXg2Na/DI=,tag:dl2x1aTsaTgtHEZYdW2lmg==,type:str] -cloudflare_dns_api_token: ENC[AES256_GCM,data:SAIMCvKOpGb5g9s03Xapc08KpOgLI+qlT5oiH/uNGxV+9JFSX3nvmQ==,iv:HFKcmHRG4EEOuJ8gRD0ZWsE18SLaZjewMSLznboLUeI=,tag:z21GURSxvNmZ4qkbri9mDQ==,type:str] +cloudflare_dns_api_token: ENC[AES256_GCM,data:QlLxQ/4AQsdqdWJC//FRgbMRqR0Ni51JgCDlyXfNe4pfPtiPs+Gb6Q==,iv:7SS+EzeHk0J1DzVvKxd40AuZUidV2asoQbSr5vyxl+U=,tag:T1KGXOsZ26sICYbrcmU8+w==,type:str] backup_password: ENC[AES256_GCM,data:Tu7ODTALfQLX7Mbo/BqiM6gaErGv07urwN1iHwGgurKWDuuE1h5NMV5J0cJqW6orTIloVtoZTJgSJ2lZlMcfUQ==,iv:78ha833ZzgEDChIuGjCMVA89U4qY9lWqUmfPCiiQeQM=,tag:u8KWw/060UVP+OOoPhbjRA==,type:str] sops: kms: [] @@ -35,8 +35,8 @@ sops: WFd4ZFNHWG5Cakw5cU9MRE9HWHQ4THMKr/S7v1Oj3zQziMtI/NuFVm6AaJF5JV5U sEr2nEptYFz4G6YL5psQGXHaKzQKBg+crgKRbYL4akhqT7pfYPC0bQ== -----END AGE ENCRYPTED FILE----- - lastmodified: "2024-05-29T22:07:18Z" - mac: ENC[AES256_GCM,data:HQJU1hZs8S4b8LAPdAg1/IuIX3VETXHrE/lKzODjCb/ndWV8Qh5v8OKg4X8xFw13PJpEeQqIznh6qplxMHJYGcYnUK/TSTP+399BZ3M0NLGWyF0vfFn1JIKu7zg8iHpi491/T+I6TDy5hp9+Y6V0sjpZ4pEzhZTwPW9t+NieSbQ=,iv:lNu0aLUO2P+2Mq7kVDGt6llshu5wgb++3VMX91w1a+8=,tag:WSoUh4XnRenvhb+vwLUpRg==,type:str] + lastmodified: "2024-07-08T00:25:56Z" + mac: ENC[AES256_GCM,data:v+p223kf9JLRMJ6moIpA5wZOemJY0+BSnX30MY8g28RBGaR+I7AbUHOrd+GUPAXLqwfqtrFdPt8pULT+fzuxL4wnlB9NPZxCYFMhSGGj8HysmDuytYXfSD1LZWD9fymE4KuyTZHv7I/coEM/iobbvutu9cmTKN05i1atjeh4B30=,iv:hPiQkvbeFjLyzTNoHMqqPikMPuDvT2X2iAo7JBlEpHY=,tag:fdHvvH+qPrv8UhwIA6aZSA==,type:str] pgp: [] unencrypted_suffix: _unencrypted version: 3.8.1 diff --git a/hosts/nixos/lapetus/default.nix b/hosts/nixos/lapetus/default.nix index 0d6eefd..e005019 100644 --- a/hosts/nixos/lapetus/default.nix +++ b/hosts/nixos/lapetus/default.nix @@ -1,4 +1,4 @@ -{ +{ config, ... }: { imports = [ ../common/global ../common/users/pilot.nix @@ -7,6 +7,7 @@ ../common/optional/services/kanata.nix ../common/optional/services/nginx.nix ../common/optional/services/postgres.nix + ../common/optional/services/syncthing.nix ../common/optional/services/restic # ./services/commafeed.nix @@ -30,7 +31,6 @@ ./services/radicale.nix ./services/redlib.nix ./services/smos.nix - ./services/syncthing.nix ./services/vaultwarden.nix ./services/whoogle.nix ./services/zfs.nix @@ -49,4 +49,18 @@ # Bootloader boot.loader.systemd-boot.enable = true; + + # Tailscale internal IP DNS records + satellite.dns.records = [ + { + at = config.networking.hostName; + type = "A"; + value = "100.93.136.59"; + } + { + at = config.networking.hostName; + type = "AAAA"; + value = "fd7a:115c:a1e0::e75d:883b"; + } + ]; } diff --git a/hosts/nixos/lapetus/services/forgejo.nix b/hosts/nixos/lapetus/services/forgejo.nix index 0b44804..0a29139 100644 --- a/hosts/nixos/lapetus/services/forgejo.nix +++ b/hosts/nixos/lapetus/services/forgejo.nix @@ -1,17 +1,12 @@ { lib, config, ... }: -let - port = config.satellite.ports.forgejo; - host = "git.moonythm.dev"; - cfg = config.services.forgejo; -in { sops.secrets.forgejo_mail_password = { sopsFile = ../secrets.yaml; - owner = cfg.user; - group = cfg.group; + owner = config.services.forgejo.user; + group = config.services.forgejo.group; }; - satellite.cloudflared.at.${host}.port = port; + satellite.cloudflared.at.git.port = config.satellite.ports.forgejo; services.forgejo = { enable = true; @@ -30,9 +25,9 @@ in default.APP_NAME = "moonforge"; server = { - DOMAIN = host; - HTTP_PORT = port; - ROOT_URL = "https://${host}"; + DOMAIN = config.satellite.cloudflared.at.git.host; + HTTP_PORT = config.satellite.cloudflared.at.git.port; + ROOT_URL = config.satellite.cloudflared.at.git.host.url; LANDING_PAGE = "prescientmoon"; # Make my profile the landing page }; diff --git a/hosts/nixos/lapetus/services/homer.nix b/hosts/nixos/lapetus/services/homer.nix index 523bb91..b7a1883 100644 --- a/hosts/nixos/lapetus/services/homer.nix +++ b/hosts/nixos/lapetus/services/homer.nix @@ -55,7 +55,7 @@ in name = "Syncthing"; subtitle = "File synchronization"; logo = icon "syncthing.png"; - url = "https://lapetus.syncthing.moonythm.dev"; + url = "https://syncthing.lapetus.moonythm.dev"; } { name = "Guacamole"; diff --git a/hosts/nixos/lapetus/services/jupyter.nix b/hosts/nixos/lapetus/services/jupyter.nix index c3bcce2..7ab8db9 100644 --- a/hosts/nixos/lapetus/services/jupyter.nix +++ b/hosts/nixos/lapetus/services/jupyter.nix @@ -18,7 +18,7 @@ in services.jupyterhub = { enable = true; - port = config.satellite.ports.jupyterhub; + port = config.satellite.cloudflared.at.jupyter.port; jupyterhubEnv = appEnv; jupyterlabEnv = appEnv; @@ -71,7 +71,7 @@ in }; # }}} # {{{ Networking & storage - satellite.cloudflared.at."jupyter.moonythm.dev".port = config.services.jupyterhub.port; + satellite.cloudflared.at.jupyter.port = config.services.jupyterhub.port; environment.persistence."/persist/state".directories = [ "/var/lib/${config.services.jupyterhub.stateDirectory}" diff --git a/hosts/nixos/lapetus/services/microbin.nix b/hosts/nixos/lapetus/services/microbin.nix index 2d186c0..9654f58 100644 --- a/hosts/nixos/lapetus/services/microbin.nix +++ b/hosts/nixos/lapetus/services/microbin.nix @@ -1,11 +1,7 @@ { config, lib, ... }: -let - port = config.satellite.ports.microbin; - host = "bin.moonythm.dev"; -in { sops.secrets.microbin_env.sopsFile = ../secrets.yaml; - satellite.cloudflared.at.${host}.port = port; + satellite.cloudflared.at.bin.port = config.satellite.ports.microbin; services.microbin = { enable = true; @@ -16,8 +12,8 @@ in settings = { # High level settings MICROBIN_ADMIN_USERNAME = "prescientmoon"; - MICROBIN_PORT = toString port; - MICROBIN_PUBLIC_PATH = "https://bin.moonythm.dev/"; + MICROBIN_PORT = toString config.satellite.cloudflared.at.bin.port; + MICROBIN_PUBLIC_PATH = config.satellite.cloudflared.at.bin.url; MICROBIN_DEFAULT_EXPIRY = "1week"; # Disable online features diff --git a/hosts/nixos/lapetus/services/pounce.nix b/hosts/nixos/lapetus/services/pounce.nix index 6be9a44..2e54995 100644 --- a/hosts/nixos/lapetus/services/pounce.nix +++ b/hosts/nixos/lapetus/services/pounce.nix @@ -28,9 +28,22 @@ in # Configure pounce services.pounce = { enable = true; - externalHost = "irc.moonythm.dev"; - bindHost = "irc.moonythm.dev"; + externalHost = "irc.${config.satellite.dns.domain}"; + bindHost = "irc.${config.satellite.dns.domain}"; certDir = "/var/lib/acme/wildcard-irc.moonythm.dev"; networks.tilde.config = config.sops.templates."pounce-tilde.cfg".path; }; + + satellite.dns.records = [ + { + type = "CNAME"; + at = "*.irc"; + to = "irc"; + } + { + type = "CNAME"; + at = "irc"; + to = config.networking.hostName; + } + ]; } diff --git a/hosts/nixos/lapetus/services/syncthing.nix b/hosts/nixos/lapetus/services/syncthing.nix deleted file mode 100644 index 6b50103..0000000 --- a/hosts/nixos/lapetus/services/syncthing.nix +++ /dev/null @@ -1,12 +0,0 @@ -{ config, ... }: -let port = 8384; -in -{ - services.syncthing = { - settings.folders = { }; - guiAddress = "127.0.0.1:${toString port}"; - settings.gui.insecureSkipHostcheck = true; - }; - - satellite.nginx.at."lapetus.syncthing".port = port; -} diff --git a/hosts/nixos/tethys/default.nix b/hosts/nixos/tethys/default.nix index 236fec4..6385482 100644 --- a/hosts/nixos/tethys/default.nix +++ b/hosts/nixos/tethys/default.nix @@ -1,4 +1,4 @@ -{ lib, pkgs, ... }: { +{ config, lib, pkgs, ... }: { # {{{ Imports imports = [ ../common/global @@ -72,4 +72,18 @@ programs.dconf.enable = true; services.gnome.evolution-data-server.enable = true; services.gnome.gnome-online-accounts.enable = true; + + # Tailscale internal IP DNS records + satellite.dns.records = [ + # { + # at = config.networking.hostName; + # type = "A"; + # value = "100.93.136.59"; + # } + # { + # at = config.networking.hostName; + # type = "AAAA"; + # value = "fd7a:115c:a1e0::e75d:883b"; + # } + ]; } diff --git a/modules/common/octodns.nix b/modules/common/octodns.nix new file mode 100644 index 0000000..2d93246 --- /dev/null +++ b/modules/common/octodns.nix @@ -0,0 +1,46 @@ +{ config, pkgs, lib, ... }: +let + format = pkgs.formats.yaml { }; + cfg = config.satellite.dns; +in +{ + options.satellite.dns.octodns = lib.mkOption { + description = "Derivation building a directory containing all the zone files"; + type = lib.types.path; + }; + + config.satellite.dns.octodns = + let + grouped = builtins.groupBy (entry: entry.zone) cfg.records; + cpLines = lib.mapAttrsToList + (zone: group: + let + grouped = builtins.groupBy (entry: entry.at) group; + contents = lib.mapAttrs + (at: entries: lib.lists.forEach entries + (entry: + let + content = + if builtins.typeOf entry.value == "list" + then { values = entry.value; } + else { inherit (entry) value; }; + cloudflare = + if entry.enableCloudflareProxy then { + octodns.cloudflare.proxied = true; + } else { }; + in + { inherit (entry) ttl type; } + // content // cloudflare + )) + grouped; + file = format.generate "${zone}.yaml" contents; + in + "cp ${file} $out/${zone}.yaml" + ) + grouped; + in + pkgs.runCommand "octodns-zones" { } '' + mkdir $out + ${lib.concatStringsSep "\n" cpLines} + ''; +} diff --git a/modules/nixos/cloudflared.nix b/modules/nixos/cloudflared.nix index 8c928e8..9c6f438 100644 --- a/modules/nixos/cloudflared.nix +++ b/modules/nixos/cloudflared.nix @@ -8,22 +8,44 @@ in description = "Cloudflare tunnel id to use for the `satellite.cloudflared.at` helper"; }; + domain = lib.mkOption { + description = "Root domain to use as a default for configurations."; + type = lib.types.str; + default = config.satellite.dns.domain; + }; + at = lib.mkOption { description = "List of hosts to set up ingress rules for"; default = { }; - type = lib.types.attrsOf (lib.types.submodule ({ name, ... }: { + type = lib.types.attrsOf (lib.types.submodule ({ name, config, ... }: { options = { + subdomain = lib.mkOption { + description = '' + Subdomain to use for host generation. + Only required if `host` is not set manually. + ''; + type = lib.types.str; + default = name; + }; + port = lib.mkOption { - type = lib.types.port; description = "Localhost port to point the tunnel at"; + type = lib.types.port; }; host = lib.mkOption { - default = name; - type = lib.types.str; description = "Host to direct traffic from"; + type = lib.types.str; + default = "${config.subdomain}.${cfg.domain}"; + }; + + url = lib.mkOption { + description = "External https url used to access this host"; + type = lib.types.str; }; }; + + config.url = "https://${config.host}"; })); }; }; @@ -34,4 +56,13 @@ in value = "http://localhost:${toString port}"; }) cfg.at; + + config.satellite.dns.records = + let mkDnsRecord = { subdomain, ... }: { + type = "CNAME"; + at = subdomain; + zone = cfg.domain; + value = "${cfg.tunnel}.cfargotunnel.com."; + }; + in lib.attrsets.mapAttrsToList (_: mkDnsRecord) cfg.at; } diff --git a/modules/nixos/default.nix b/modules/nixos/default.nix index 4f811fa..e4e197f 100644 --- a/modules/nixos/default.nix +++ b/modules/nixos/default.nix @@ -7,4 +7,6 @@ nginx = import ./nginx.nix; pilot = import ./pilot.nix; pounce = import ./pounce.nix; + dns = import ./dns.nix; + dns-assertions = import ./dns-assertions.nix; } diff --git a/modules/nixos/dns-assertions.nix b/modules/nixos/dns-assertions.nix new file mode 100644 index 0000000..d1409f9 --- /dev/null +++ b/modules/nixos/dns-assertions.nix @@ -0,0 +1,17 @@ +# This must only be loaded on actual Nixos, otherwise `assertions` +# won't be defined when running `evaluateModules`. +{ config, ... }: +let cfg = config.satellite.dns; +in +{ + config.assertions = + let assertProperToUsage = config: + { + assertion = (config.to == null) || (config.type == "CNAME"); + message = '' + The option `satellite.dns.records[*].to` can only be used with `CNAME` records. + This was not the case for ${config.type} record at ${config.at}.${config.zone}. + ''; + }; + in builtins.map assertProperToUsage cfg.records; +} diff --git a/modules/nixos/dns.nix b/modules/nixos/dns.nix new file mode 100644 index 0000000..edaad21 --- /dev/null +++ b/modules/nixos/dns.nix @@ -0,0 +1,59 @@ +{ config, pkgs, lib, ... }: +let + format = pkgs.formats.yaml { }; + cfg = config.satellite.dns; +in +{ + options.satellite.dns = { + domain = lib.mkOption { + description = "Default zone to include records in"; + type = lib.types.str; + }; + + records = lib.mkOption { + description = "List of records to create"; + default = [ ]; + type = lib.types.listOf (lib.types.submodule ({ config, ... }: { + options = { + at = lib.mkOption { + description = "Subdomain to use for entry"; + type = lib.types.nullOr lib.types.str; + }; + + zone = lib.mkOption { + description = "Zone this record is a part of"; + type = lib.types.str; + default = cfg.domain; + }; + + type = lib.mkOption { + type = lib.types.enum [ "A" "AAAA" "TXT" "CNAME" "MX" ]; + description = "The type of the DNS record"; + }; + + to = lib.mkOption { + type = lib.types.nullOr lib.types.str; + description = "Shorthand for CNMAE-ing to a subdomain of the given zone"; + default = null; + }; + + value = lib.mkOption { + type = format.type; + description = "The value assigned to the record, in octodns format"; + }; + + ttl = lib.mkOption { + type = lib.types.int; + description = "The TTL assigned to the record"; + default = 300; + }; + + enableCloudflareProxy = lib.mkEnableOption "proxying using cloudflare"; + }; + + config.value = lib.mkIf (config.type == "CNAME" && config.to != null) + "${config.to}.${config.zone}."; + })); + }; + }; +} diff --git a/modules/nixos/nginx.nix b/modules/nixos/nginx.nix index 6a2fa6b..9066e62 100644 --- a/modules/nixos/nginx.nix +++ b/modules/nixos/nginx.nix @@ -6,24 +6,28 @@ in domain = lib.mkOption { description = "Root domain to use as a default for configurations."; type = lib.types.str; + default = config.satellite.dns.domain; }; at = lib.mkOption { description = "Per-subdomain nginx configuration"; type = lib.types.attrsOf (lib.types.submodule ({ name, config, ... }: { - options.name = lib.mkOption { - description = "Attribute name leading to this submodule"; + options.subdomain = lib.mkOption { + description = '' + Subdomain to use for host generation. + Only required if `host` is not set manually. + ''; type = lib.types.str; + default = name; }; - config.name = name; - options.host = lib.mkOption { description = "Host to route requests from"; type = lib.types.str; - default = "${name}.${cfg.domain}"; }; + config.host = "${config.subdomain}.${cfg.domain}"; + options.url = lib.mkOption { description = "External https url used to access this host"; type = lib.types.str; @@ -53,8 +57,8 @@ in { assertion = (config.port == null) == (config.files != null); message = '' - Precisely one of the options 'satellite.nginx.at.${config.name}.port' - and 'satellite.nginx.at.${config.name}.files' must be specified. + Precisely one of the options 'satellite.nginx.at.${config.subdomain}.port' + and 'satellite.nginx.at.${config.subdomain}.files' must be specified. ''; }; in lib.mapAttrsToList (_: assertSingleTarget) cfg.at; @@ -81,5 +85,14 @@ in } // extra; }; in lib.attrsets.mapAttrs' (_: mkNginxConfig) cfg.at; + + satellite.dns.records = + let mkDnsRecord = { subdomain, ... }: { + type = "CNAME"; + zone = cfg.domain; + at = subdomain; + to = config.networking.hostName; + }; + in lib.attrsets.mapAttrsToList (_: mkDnsRecord) cfg.at; }; } diff --git a/pkgs/default.nix b/pkgs/default.nix index 198747f..9763bca 100644 --- a/pkgs/default.nix +++ b/pkgs/default.nix @@ -1,7 +1,7 @@ # Custom packages, that can be defined similarly to ones from nixpkgs # You can build them using 'nix build .#example' or (legacy) 'nix-build -A example' -{ pkgs ? (import ../nixpkgs.nix) { }, upkgs ? pkgs }: +{ pkgs ? (import ../nixpkgs.nix) { }, upkgs ? pkgs, ... }: let plymouthThemes = pkgs.callPackage (import ./plymouth-themes.nix) { }; in { # example = pkgs.callPackage (import ./example.nix) {}; diff --git a/pkgs/octodns-cloudflare.nix b/pkgs/octodns-cloudflare.nix new file mode 100644 index 0000000..e960238 --- /dev/null +++ b/pkgs/octodns-cloudflare.nix @@ -0,0 +1,45 @@ +{ lib +, buildPythonPackage +, fetchFromGitHub +, octodns +, pytestCheckHook +, pythonOlder +, dnspython +, setuptools +, requests +, requests-mock +}: + +buildPythonPackage rec { + pname = "octodns-cloudflare"; + version = "unstable-2024-05-31"; + pyproject = true; + + disabled = pythonOlder "3.8"; + + src = fetchFromGitHub { + owner = "octodns"; + repo = "octodns-cloudflare"; + rev = "3c01938e280767f433eb276a75d6b02c152c02af"; + sha256 = "1dnvyvf6mlpqcsrj11192li2mhqfs8w6pvaqmsy3jsqjqczmgmf5"; + }; + + nativeBuildInputs = [ + setuptools + ]; + + propagatedBuildInputs = [ + octodns + dnspython + requests + ]; + + env.OCTODNS_RELEASE = 1; + + pythonImportsCheck = [ "octodns_cloudflare" ]; + + nativeCheckInputs = [ + pytestCheckHook + requests-mock + ]; +} diff --git a/scripts/dns/dns.txt b/scripts/dns/dns.txt index 670816a..ee9445d 100644 --- a/scripts/dns/dns.txt +++ b/scripts/dns/dns.txt @@ -34,7 +34,7 @@ yt IN CNAME lapetus *.irc IN CNAME irc ; Tunnel used by lapetus -tunnel.lapetus IN CNAME 347d9ead-a523-4f8b-bca7-3066e31e2952.cfargotunnel.com +tunnel.lapetus IN CNAME 347d9ead-a523-4f8b-bca7-3066e31e2952.cfargotunnel.com. ; lapetus services using cloudflare tunnels bin IN CNAME tunnel.lapetus