Working on DNS

This commit is contained in:
niten 2022-01-10 13:05:38 -08:00
parent ffbe3656ec
commit 63b80fb5dc
5 changed files with 113 additions and 162 deletions

View File

@ -27,64 +27,11 @@ let
};
};
# networkHostOpts = import ../types/network-host.nix { inherit lib; };
# hostRecords = hostname: nethost-data: let
# # FIXME: RP doesn't work.
# # generic-host-records = let
# # host-data = if (hasAttr hostname config.fudo.hosts) then config.fudo.hosts.${hostname} else null;
# # in
# # if (host-data == null) then [] else (
# # (map (sshfp: "${hostname} IN SSHFP ${sshfp}") host-data.ssh-fingerprints) ++ (optional (host-data.rp != null) "${hostname} IN RP ${host-data.rp}")
# # );
# sshfp-records = if (hasAttr hostname config.fudo.hosts) then
# (map (sshfp: "${hostname} IN SSHFP ${sshfp}")
# config.fudo.hosts.${hostname}.ssh-fingerprints)
# else [];
# a-record = optional (nethost-data.ipv4-address != null) "${hostname} IN A ${nethost-data.ipv4-address}";
# aaaa-record = optional (nethost-data.ipv6-address != null) "${hostname} IN AAAA ${nethost-data.ipv6-address}";
# description-record = optional (nethost-data.description != null) "${hostname} IN TXT \"${nethost-data.description}\"";
# in
# join-lines (a-record ++ aaaa-record ++ description-record ++ sshfp-records);
# makeSrvRecords = protocol: type: records:
# join-lines (map (record:
# "_${type}._${protocol} IN SRV ${toString record.priority} ${
# toString record.weight
# } ${toString record.port} ${toString record.host}.") records);
# makeSrvProtocolRecords = protocol: types:
# join-lines (mapAttrsToList (makeSrvRecords protocol) types);
# cnameRecord = alias: host: "${alias} IN CNAME ${host}";
# mxRecords = mxs: concatStringsSep "\n" (map (mx: "@ IN MX 10 ${mx}.") mxs);
# dmarcRecord = dmarc-email:
# optionalString (dmarc-email != null) ''
# _dmarc IN TXT "v=DMARC1;p=quarantine;sp=quarantine;rua=mailto:${dmarc-email};"'';
# nsRecords = domain: ns-hosts:
# join-lines
# (mapAttrsToList (host: _: "@ IN NS ${host}.${domain}.") ns-hosts);
in {
options.fudo.dns = with types; {
enable = mkEnableOption "Enable master DNS services.";
# FIXME: This should allow for AAAA addresses too...
# nameservers = mkOption {
# type = attrsOf (submodule networkHostOpts);
# description = "Map of domain nameserver FQDNs to IP.";
# example = {
# "ns1.domain.com" = {
# ipv4-address = "1.1.1.1";
# description = "my fancy dns server";
# };
# };
# };
identity = mkOption {
type = str;
description = "The identity (CH TXT ID.SERVER) of this host.";
@ -131,38 +78,6 @@ in {
dom
dom-cfg.zone-definition;
# data = ''
# $ORIGIN ${dom}.
# $TTL 12h
# @ IN SOA ns1.${dom}. hostmaster.${dom}. (
# ${toString config.instance.build-timestamp}
# 30m
# 2m
# 3w
# 5m)
# ${optionalString (dom-cfg.default-host != null)
# "@ IN A ${dom-cfg.default-host}"}
# ${mxRecords dom-cfg.mx}
# $TTL 6h
# ${optionalString (dom-cfg.gssapi-realm != null)
# ''_kerberos IN TXT "${dom-cfg.gssapi-realm}"''}
# ${nsRecords dom cfg.nameservers}
# ${join-lines (mapAttrsToList hostRecords cfg.nameservers)}
# ${dmarcRecord dom-cfg.dmarc-report-address}
# ${join-lines
# (mapAttrsToList makeSrvProtocolRecords net-cfg.srv-records)}
# ${join-lines (mapAttrsToList hostRecords net-cfg.hosts)}
# ${join-lines (mapAttrsToList cnameRecord net-cfg.aliases)}
# ${join-lines net-cfg.verbatim-dns-records}
# '';
}) cfg.domains;
};
};

View File

@ -5,22 +5,31 @@ let
inherit (lib.strings) concatStringsSep;
cfg = config.fudo.node-exporter;
fudo-cfg = config.fudo.common;
allow-network = network: "allow ${network};";
local-networks = config.instance.local-networks;
in {
options.fudo.node-exporter = {
options.fudo.node-exporter = with types; {
enable = mkEnableOption "Enable a Prometheus node exporter with some reasonable settings.";
hostname = mkOption {
type = types.str;
type = str;
description = "Hostname from which to export statistics.";
};
user = mkOption {
type = str;
description = "User as which to run the node exporter job.";
default = "node-exporter";
};
};
config = mkIf cfg.enable {
security.acme.certs.${cfg.hostname}.email = fudo-cfg.admin-email;
users.users.${cfg.user} = {
isSystemUser = true;
};
services = {
# This'll run an exporter at localhost:9100
@ -29,7 +38,7 @@ in {
enabledCollectors = [ "systemd" ];
listenAddress = "127.0.0.1";
port = 9100;
user = "node";
user = cfg.user;
};
# ...And this'll expose the above to the outside world, or at least the
@ -43,7 +52,7 @@ in {
locations."/metrics/node" = {
extraConfig = ''
${concatStringsSep "\n" (map allow-network fudo-cfg.local-networks)}
${concatStringsSep "\n" (map allow-network local-networks)}
allow 127.0.0.0/16;
deny all;

View File

@ -4,16 +4,60 @@ with pkgs.lib;
let
join-lines = concatStringsSep "\n";
dump = obj: builtins.trace obj obj;
pthru = obj: builtins.trace obj obj;
remove-blank-lines = str:
concatStringsSep "\n\n"
(filter builtins.isString
(builtins.split "\n\n\n+" str));
n-spaces = n:
concatStringsSep "" (builtins.genList (_: " ") n);
pad-to-length = strlen: str: let
spaces = n-spaces (strlen - (stringLength str));
in str + spaces;
record-matcher = builtins.match "^([^;].*) IN ([A-Z][A-Z0-9]*) (.+)$";
is-record = str: (record-matcher str) != null;
max-int = foldr (a: b: if (a < b) then b else a) 0;
make-zone-formatter = zonedata: let
lines = splitString "\n" zonedata;
records = filter is-record lines;
split-records = map record-matcher records;
index-strlen = i: record: stringLength (elemAt record i);
record-index-maxlen = i: max-int (map (index-strlen i) split-records);
in record-formatter (record-index-maxlen 0) (record-index-maxlen 1);
record-formatter = name-max: type-max: let
name-padder = pad-to-length name-max;
type-padder = pad-to-length type-max;
in record-line: let
record-parts = record-matcher record-line;
in
if (record-parts == null) then
record-line
else (let
name = elemAt record-parts 0;
type = elemAt record-parts 1;
data = elemAt record-parts 2;
in "${name-padder name} IN ${type-padder type} ${data}");
format-zone = zonedata: let
formatter = make-zone-formatter zonedata;
lines = splitString "\n" zonedata;
in concatStringsSep "\n" (map formatter lines);
makeSrvRecords = protocol: service: records: let
service-blah = (dump service);
record-blah = (dump records);
in
join-lines (map (record:
"_${service}._${protocol} IN SRV ${toString record.priority} ${
toString record.weight
} ${toString record.port} ${record.host}.") records);
service-blah = service;
record-blah = records;
in join-lines (map (record:
"_${service}._${protocol} IN SRV ${toString record.priority} ${
toString record.weight
} ${toString record.port} ${record.host}.") records);
makeSrvProtocolRecords = protocol: services:
join-lines (mapAttrsToList (makeSrvRecords protocol) services);
@ -52,10 +96,15 @@ let
"${hostname} IN A ${nethost-data.ipv4-address}";
aaaa-record = optional (nethost-data.ipv6-address != null)
"${hostname} IN AAAA ${nethost-data.ipv6-address}";
cname-record = optional (nethost-data.authoritative-hostname != null)
"${hostname} IN CNAME ${nethost-data.authoritative-hostname}";
description-record = optional (nethost-data.description != null)
''${hostname} IN TXT "${nethost-data.description}"'';
in
join-lines (a-record ++ aaaa-record ++ description-record ++ sshfp-records);
in join-lines (a-record ++
aaaa-record ++
cname-record ++
sshfp-records ++
description-record);
cnameRecord = alias: host: "${alias} IN CNAME ${host}";
@ -71,19 +120,19 @@ let
flatmapAttrsToList = f: attrs:
foldr (a: b: a ++ b) [] (mapAttrsToList f attrs);
nsARecords = _: ns-hosts: let
a-record = host: hostOpts: optional (hostOpts.ipv4-address != null)
"${host} IN A ${hostOpts.ipv4-address}";
aaaa-record = host: hostOpts: optional (hostOpts.ipv6-address != null)
"${host} IN AAAA ${hostOpts.ipv6-address}";
description-record = host: hostOpts: optional (hostOpts.description != null)
''${host} IN TXT "${hostOpts.description}"'';
in flatmapAttrsToList
(host: hostOpts:
(a-record host hostOpts) ++
(aaaa-record host hostOpts) ++
(description-record host hostOpts))
ns-hosts;
# nsARecords = _: ns-hosts: let
# a-record = host: hostOpts: optional (hostOpts.ipv4-address != null)
# "${host} IN A ${hostOpts.ipv4-address}";
# aaaa-record = host: hostOpts: optional (hostOpts.ipv6-address != null)
# "${host} IN AAAA ${hostOpts.ipv6-address}";
# description-record = host: hostOpts: optional (hostOpts.description != null)
# ''${host} IN TXT "${hostOpts.description}"'';
# in flatmapAttrsToList
# (host: hostOpts:
# (a-record host hostOpts) ++
# (aaaa-record host hostOpts) ++
# (description-record host hostOpts))
# ns-hosts;
srvRecordPair = domain: protocol: service: record: {
@ -97,63 +146,32 @@ let
$ORIGIN ${dom}.
$TTL ${zone.default-ttl}
###
# Default Host
###
${optionalString (zone.default-host != null)
"@ IN A ${zone.default-host}"}
###
# MX Records
###
${join-lines (mxRecords zone.mx)}
# dmarc
${dmarcRecord zone.dmarc-report-address}
###
# Kerberos Realm
###
${optionalString (zone.gssapi-realm != null)
''_kerberos IN TXT "${zone.gssapi-realm}"''}
###
# Nameservers
###
${join-lines (nsRecords dom zone.nameservers)}
${join-lines (nsARecords dom zone.nameservers)}
${join-lines (mapAttrsToList hostRecords zone.nameservers)}
###
# General Records
###
$TTL ${zone.host-record-ttl}
###
# SRV Records
###
${join-lines (mapAttrsToList makeSrvProtocolRecords zone.srv-records)}
###
# Host Records
###
$TTL ${zone.host-record-ttl}
${join-lines (mapAttrsToList hostRecords zone.hosts)}
###
# CNAMEs
###
${join-lines (mapAttrsToList cnameRecord zone.aliases)}
###
# Verbatim Records
###
${join-lines zone.verbatim-dns-records}
###
# Subdomains of ${dom}
###
${join-lines (mapAttrsToList
(subdom: subdomCfg: subdomain-record "${subdom}.${dom}" subdomCfg)
(subdom: subdomCfg: domain-record "${subdom}.${dom}" subdomCfg)
zone.subdomains)}
'';
@ -173,17 +191,18 @@ in rec {
(service: records: map (srvRecordPair domain protocol service) records) services)
srvRecords);
zoneToZonefile = timestamp: dom: zone: ''
$ORIGIN ${dom}.
$TTL ${zone.default-ttl}
zoneToZonefile = timestamp: dom: zone:
remove-blank-lines (format-zone ''
$ORIGIN ${dom}.
$TTL ${zone.default-ttl}
@ IN SOA ns1.${dom}. hostmaster.${dom}. (
${toString timestamp}
30m
2m
3w
5m)
@ IN SOA ns1.${dom}. hostmaster.${dom}. (
${toString timestamp}
30m
2m
3w
5m)
${domain-record dom zone}
'';
${domain-record dom zone}
'');
}

View File

@ -27,6 +27,8 @@ let
import-by-basename = path:
mapAttrs (attr: attr-file: import attr-file)
(basename-to-file-map path);
list-nix-files = nix-files;
in {
inherit basename-to-file-map import-by-basename;
inherit basename-to-file-map import-by-basename list-nix-files;
}

View File

@ -1,6 +1,5 @@
{ lib, ... }:
{ hostname, ... }:
with lib;
{
options = with types; {
@ -23,6 +22,13 @@ with lib;
default = null;
};
authoritative-hostname = mkOption {
type = nullOr str;
description =
"The 'real' hostname of this host, i.e. CNAME. Prefer aliases!";
default = null;
};
description = mkOption {
type = nullOr str;
description = "Description of the host.";