feat(state): consolidate, update module, enslave dns entries

This commit is contained in:
Malte Tammena 2024-11-17 18:07:28 +01:00
parent 7449ab4dee
commit b7954dfd8b
4 changed files with 124 additions and 94 deletions

View file

@ -1,10 +1,8 @@
{ {
pkgs,
lib, lib,
config, config,
... ...
}: let }: let
state = builtins.import ../../state.nix;
mkVirtHost = lib.attrsets.recursiveUpdate { mkVirtHost = lib.attrsets.recursiveUpdate {
forceSSL = true; forceSSL = true;
enableACME = true; enableACME = true;
@ -14,6 +12,7 @@ in {
../../hardware/netcup-vps-200-g10.nix ../../hardware/netcup-vps-200-g10.nix
../../modules/nginx-reverse-proxy.nix ../../modules/nginx-reverse-proxy.nix
./modules/murmur.nix ./modules/murmur.nix
./modules/vpn-dns.nix
./topology.nix ./topology.nix
]; ];
config = { config = {
@ -32,14 +31,11 @@ in {
}; };
}; };
sops.defaultSopsFile = ../../secrets/hosts/granodomus-lima/secrets.yaml;
sops.age.sshKeyPaths = ["/etc/ssh/ssh_host_ed25519_key"];
services.fail2ban = { services.fail2ban = {
enable = true; enable = true;
ignoreIP = let ignoreIP = let
vpn = state.vpn; vpn = config.state.vpn.machine;
extractIPs = _: config: [config.v4 config.v6]; extractIPs = _: config: [config.ipv4 config.ipv6];
in in
lib.flatten (lib.attrsets.mapAttrsToList extractIPs vpn); lib.flatten (lib.attrsets.mapAttrsToList extractIPs vpn);
}; };
@ -48,13 +44,13 @@ in {
services.radicaleWithInfcloud.enable = true; services.radicaleWithInfcloud.enable = true;
services.nginx.virtualHosts = let services.nginx.virtualHosts = let
services = state.services; services = config.state.services;
removeUnexposed = lib.attrsets.filterAttrs (_: config: config ? "external" && config.external); removeUnexposed = lib.attrsets.filterAttrs (_: config: config ? "external" && config.external);
createVirtHost = name: config: { createVirtHost = name: cfg: {
name = "${name}.tammena.me"; name = "${name}.tammena.me";
value = mkVirtHost { value = mkVirtHost {
locations."/" = { locations."/" = {
proxyPass = let ip = state.vpn.${config.host}.v4; in "http://${ip}:${builtins.toString config.port}"; proxyPass = let ip = config.state.vpn.machine.${cfg.host}.ipv4; in "http://${ip}:${builtins.toString cfg.port}";
proxyWebsockets = true; proxyWebsockets = true;
}; };
extraConfig = extraConfig =
@ -70,7 +66,7 @@ in {
services.nginx.appendConfig = '' services.nginx.appendConfig = ''
stream { stream {
upstream ssh { upstream ssh {
server ${state.services.git.host}:22; server ${config.state.services.git.host}:22;
} }
server { server {
listen 22222; listen 22222;
@ -79,66 +75,12 @@ in {
} }
} }
''; '';
networking.firewall.allowedTCPPorts = [22222];
services.qemuGuest.enable = true; services.qemuGuest.enable = true;
services.bind = { sops.defaultSopsFile = ../../secrets/hosts/granodomus-lima/secrets.yaml;
enable = true; sops.age.sshKeyPaths = ["/etc/ssh/ssh_host_ed25519_key"];
cacheNetworks = ["any"];
forwarders = ["100.100.100.100"];
listenOn = ["any"];
listenOnIpv6 = ["any"];
zones."home" = let
granodomus-lima = config.state.vpn.machine.granodomus-lima;
faunus-ater = config.state.vpn.machine.faunus-ater;
point = domain: host: ''
${domain} AAAA ${host.ipv6}
${domain} A ${host.ipv4}
'';
in {
master = true;
# TODO: Fix TTLs
file = pkgs.writeText "home-zone" ''
$TTL 1
@ IN SOA home. malte.home. (
5 ; Serial
1 ; Refresh
1 ; Retry
1 ; Expire
1) ; Negative Cache TTL
@ NS home.
${point "home." granodomus-lima}
${point "cal" granodomus-lima}
${point "mc" granodomus-lima}
${point "foto" faunus-ater}
${point "doc" faunus-ater}
${point "sheet" faunus-ater}
${point "media" faunus-ater}
${point "file" faunus-ater}
${point "stats" faunus-ater}
${point "cache" faunus-ater}
${point "hydra" faunus-ater}
${point "git" faunus-ater}
${point "read" faunus-ater}
${point "note" faunus-ater}
${point "time" faunus-ater}
${point "todo" faunus-ater}
${point "config" faunus-ater}
${point "listen" faunus-ater}
${point "eat" faunus-ater}
${point "sea" faunus-ater}
${point "s3" faunus-ater}
${point "bazarr" faunus-ater}
${point "sonarr" faunus-ater}
${point "radarr" faunus-ater}
${point "prowlarr" faunus-ater}
${point "downloadarr" faunus-ater}
${point "music" faunus-ater}
'';
};
};
networking.firewall.allowedTCPPorts = [53 22222];
networking.firewall.allowedUDPPorts = [53];
# This value determines the NixOS release from which the default # This value determines the NixOS release from which the default
# settings for stateful data, like file locations and database versions # settings for stateful data, like file locations and database versions

View file

@ -0,0 +1,43 @@
{
pkgs,
lib,
config,
...
}: let
thisHost = config.networking.hostName;
in {
services.bind = {
enable = true;
cacheNetworks = ["any"];
forwarders = ["100.100.100.100"];
listenOn = ["any"];
listenOnIpv6 = ["any"];
zones."home" = let
createEntry = domain: host: ''
${domain} AAAA ${config.state.vpn.machine.${host}.ipv6}
${domain} A ${config.state.vpn.machine.${host}.ipv4}
'';
entries = builtins.concatStringsSep "" (lib.mapAttrsToList createEntry config.state.vpn.cnames);
in {
master = true;
# TODO: Fix TTLs
file = pkgs.writeText "home-zone" ''
$TTL 3600
@ IN SOA home. malte.home. (
2024111701 ; Serial
3600 ; Refresh
1800 ; Retry
604800 ; Expire
86400) ; Negative Cache TTL
@ NS home.
home. AAAA ${config.state.vpn.machine.${thisHost}.ipv6}
home. A ${config.state.vpn.machine.${thisHost}.ipv4}
${entries}
'';
};
};
networking.firewall.allowedTCPPorts = [53];
networking.firewall.allowedUDPPorts = [53];
}

View file

@ -5,7 +5,8 @@
}: let }: let
state = builtins.import ../state.nix; state = builtins.import ../state.nix;
ty = { ty = {
ipv4 = lib.types.strMatching "[0-9]{1,3}(\\.[0-9]{1,3}){3}"; ipv4 = lib.types.strMatching "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}";
ipv6 = lib.types.strMatching "(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))";
}; };
in { in {
options.state = with lib; { options.state = with lib; {
@ -28,7 +29,7 @@ in {
description = "VPN IPv4"; description = "VPN IPv4";
}; };
ipv6 = mkOption { ipv6 = mkOption {
type = str; type = ty.ipv6;
description = "VPN IPv6"; description = "VPN IPv6";
}; };
}; };
@ -41,6 +42,11 @@ in {
description = "VPN internal DNS server address"; description = "VPN internal DNS server address";
readOnly = true; readOnly = true;
}; };
vpn.cnames = mkOption {
type = types.attrsOf types.str;
description = "CNAMES for our internal DNS server";
readOnly = true;
};
services = mkOption { services = mkOption {
type = with types; type = with types;
attrsOf (submodule { attrsOf (submodule {
@ -78,12 +84,24 @@ in {
vpn.machine = vpn.machine =
if state ? vpn if state ? vpn
then then
builtins.mapAttrs (machine: conf: { builtins.mapAttrs (_: conf: {
ipv4 = conf.v4; ipv4 = conf.v4;
ipv6 = conf.v6; ipv6 = conf.v6;
}) })
state.vpn state.vpn
else builtins.throw "No VPN definitions"; else builtins.throw "No VPN definitions";
vpn.dns =
if state ? services && state.services ? dns
then
(
if state ? vpn && state.vpn ? "${state.services.dns.host}"
then state.vpn.${state.services.dns.host}.v4
else builtins.throw "No VPN entry for DNS host"
)
else builtins.throw "No DNS service defined!";
vpn.cnames = (if state ? cnames then state.cnames else {}) // (
builtins.mapAttrs (_name: value: value.host) config.state.services
);
services = services =
if state ? services if state ? services
then state.services then state.services

View file

@ -37,24 +37,14 @@
# Information about which services run where # Information about which services run where
# Type: attrsOf { host: str, port: number, external: bool } # Type: attrsOf { host: str, port: number, external: bool }
services = { services = {
git = { calibre = {
host = "faunus-ater"; host = "faunus-ater";
port = 10219; port = 12834;
external = true; external = true;
}; };
read = { dns = {
host = "faunus-ater"; host = "granodomus-lima";
port = 10224; port = 53;
external = true;
};
foto = {
host = "faunus-ater";
port = 2343;
external = true;
};
eat = {
host = "faunus-ater";
port = 9000;
external = true; external = true;
}; };
doc = { doc = {
@ -62,25 +52,62 @@
port = 28981; port = 28981;
external = true; external = true;
}; };
sea = { eat = {
host = "faunus-ater"; host = "faunus-ater";
port = 9333; port = 9000;
external = false; external = true;
}; };
s3 = { foto = {
host = "faunus-ater"; host = "faunus-ater";
port = 8333; port = 2343;
external = false; external = true;
};
git = {
host = "faunus-ater";
port = 10219;
external = true;
}; };
music = { music = {
host = "faunus-ater"; host = "faunus-ater";
port = 4533; port = 4533;
external = true; external = true;
}; };
calibre = { read = {
host = "faunus-ater"; host = "faunus-ater";
port = 12834; port = 10224;
external = true; external = true;
}; };
s3 = {
host = "faunus-ater";
port = 8333;
external = false;
};
sea = {
host = "faunus-ater";
port = 9333;
external = false;
};
};
#### CNAMES ####
# CNAMES inside my vpn, service-entries don't have to be repeated here
cnames = {
bazarr = "faunus-ater";
cache = "faunus-ater";
cal = "granodomus-lima";
config = "faunus-ater";
downloadarr = "faunus-ater";
file = "faunus-ater";
hydra = "faunus-ater";
listen = "faunus-ater";
mc = "granodomus-lima";
media = "faunus-ater";
note = "faunus-ater";
prowlarr = "faunus-ater";
radarr = "faunus-ater";
sheet = "faunus-ater";
sonarr = "faunus-ater";
stats = "faunus-ater";
time = "faunus-ater";
todo = "faunus-ater";
}; };
} }