Working on DNS
This commit is contained in:
parent
ffbe3656ec
commit
63b80fb5dc
@ -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 {
|
in {
|
||||||
|
|
||||||
options.fudo.dns = with types; {
|
options.fudo.dns = with types; {
|
||||||
enable = mkEnableOption "Enable master DNS services.";
|
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 {
|
identity = mkOption {
|
||||||
type = str;
|
type = str;
|
||||||
description = "The identity (CH TXT ID.SERVER) of this host.";
|
description = "The identity (CH TXT ID.SERVER) of this host.";
|
||||||
@ -131,38 +78,6 @@ in {
|
|||||||
dom
|
dom
|
||||||
dom-cfg.zone-definition;
|
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;
|
}) cfg.domains;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -5,22 +5,31 @@ let
|
|||||||
inherit (lib.strings) concatStringsSep;
|
inherit (lib.strings) concatStringsSep;
|
||||||
|
|
||||||
cfg = config.fudo.node-exporter;
|
cfg = config.fudo.node-exporter;
|
||||||
fudo-cfg = config.fudo.common;
|
|
||||||
|
|
||||||
allow-network = network: "allow ${network};";
|
allow-network = network: "allow ${network};";
|
||||||
|
|
||||||
|
local-networks = config.instance.local-networks;
|
||||||
|
|
||||||
in {
|
in {
|
||||||
options.fudo.node-exporter = {
|
options.fudo.node-exporter = with types; {
|
||||||
enable = mkEnableOption "Enable a Prometheus node exporter with some reasonable settings.";
|
enable = mkEnableOption "Enable a Prometheus node exporter with some reasonable settings.";
|
||||||
|
|
||||||
hostname = mkOption {
|
hostname = mkOption {
|
||||||
type = types.str;
|
type = str;
|
||||||
description = "Hostname from which to export statistics.";
|
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 {
|
config = mkIf cfg.enable {
|
||||||
security.acme.certs.${cfg.hostname}.email = fudo-cfg.admin-email;
|
users.users.${cfg.user} = {
|
||||||
|
isSystemUser = true;
|
||||||
|
};
|
||||||
|
|
||||||
services = {
|
services = {
|
||||||
# This'll run an exporter at localhost:9100
|
# This'll run an exporter at localhost:9100
|
||||||
@ -29,7 +38,7 @@ in {
|
|||||||
enabledCollectors = [ "systemd" ];
|
enabledCollectors = [ "systemd" ];
|
||||||
listenAddress = "127.0.0.1";
|
listenAddress = "127.0.0.1";
|
||||||
port = 9100;
|
port = 9100;
|
||||||
user = "node";
|
user = cfg.user;
|
||||||
};
|
};
|
||||||
|
|
||||||
# ...And this'll expose the above to the outside world, or at least the
|
# ...And this'll expose the above to the outside world, or at least the
|
||||||
@ -43,7 +52,7 @@ in {
|
|||||||
|
|
||||||
locations."/metrics/node" = {
|
locations."/metrics/node" = {
|
||||||
extraConfig = ''
|
extraConfig = ''
|
||||||
${concatStringsSep "\n" (map allow-network fudo-cfg.local-networks)}
|
${concatStringsSep "\n" (map allow-network local-networks)}
|
||||||
allow 127.0.0.0/16;
|
allow 127.0.0.0/16;
|
||||||
deny all;
|
deny all;
|
||||||
|
|
||||||
|
157
lib/lib/dns.nix
157
lib/lib/dns.nix
@ -4,16 +4,60 @@ with pkgs.lib;
|
|||||||
let
|
let
|
||||||
join-lines = concatStringsSep "\n";
|
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
|
makeSrvRecords = protocol: service: records: let
|
||||||
service-blah = (dump service);
|
service-blah = service;
|
||||||
record-blah = (dump records);
|
record-blah = records;
|
||||||
in
|
in join-lines (map (record:
|
||||||
join-lines (map (record:
|
"_${service}._${protocol} IN SRV ${toString record.priority} ${
|
||||||
"_${service}._${protocol} IN SRV ${toString record.priority} ${
|
toString record.weight
|
||||||
toString record.weight
|
} ${toString record.port} ${record.host}.") records);
|
||||||
} ${toString record.port} ${record.host}.") records);
|
|
||||||
|
|
||||||
makeSrvProtocolRecords = protocol: services:
|
makeSrvProtocolRecords = protocol: services:
|
||||||
join-lines (mapAttrsToList (makeSrvRecords protocol) services);
|
join-lines (mapAttrsToList (makeSrvRecords protocol) services);
|
||||||
@ -52,10 +96,15 @@ let
|
|||||||
"${hostname} IN A ${nethost-data.ipv4-address}";
|
"${hostname} IN A ${nethost-data.ipv4-address}";
|
||||||
aaaa-record = optional (nethost-data.ipv6-address != null)
|
aaaa-record = optional (nethost-data.ipv6-address != null)
|
||||||
"${hostname} IN AAAA ${nethost-data.ipv6-address}";
|
"${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)
|
description-record = optional (nethost-data.description != null)
|
||||||
''${hostname} IN TXT "${nethost-data.description}"'';
|
''${hostname} IN TXT "${nethost-data.description}"'';
|
||||||
in
|
in join-lines (a-record ++
|
||||||
join-lines (a-record ++ aaaa-record ++ description-record ++ sshfp-records);
|
aaaa-record ++
|
||||||
|
cname-record ++
|
||||||
|
sshfp-records ++
|
||||||
|
description-record);
|
||||||
|
|
||||||
cnameRecord = alias: host: "${alias} IN CNAME ${host}";
|
cnameRecord = alias: host: "${alias} IN CNAME ${host}";
|
||||||
|
|
||||||
@ -71,19 +120,19 @@ let
|
|||||||
flatmapAttrsToList = f: attrs:
|
flatmapAttrsToList = f: attrs:
|
||||||
foldr (a: b: a ++ b) [] (mapAttrsToList f attrs);
|
foldr (a: b: a ++ b) [] (mapAttrsToList f attrs);
|
||||||
|
|
||||||
nsARecords = _: ns-hosts: let
|
# nsARecords = _: ns-hosts: let
|
||||||
a-record = host: hostOpts: optional (hostOpts.ipv4-address != null)
|
# a-record = host: hostOpts: optional (hostOpts.ipv4-address != null)
|
||||||
"${host} IN A ${hostOpts.ipv4-address}";
|
# "${host} IN A ${hostOpts.ipv4-address}";
|
||||||
aaaa-record = host: hostOpts: optional (hostOpts.ipv6-address != null)
|
# aaaa-record = host: hostOpts: optional (hostOpts.ipv6-address != null)
|
||||||
"${host} IN AAAA ${hostOpts.ipv6-address}";
|
# "${host} IN AAAA ${hostOpts.ipv6-address}";
|
||||||
description-record = host: hostOpts: optional (hostOpts.description != null)
|
# description-record = host: hostOpts: optional (hostOpts.description != null)
|
||||||
''${host} IN TXT "${hostOpts.description}"'';
|
# ''${host} IN TXT "${hostOpts.description}"'';
|
||||||
in flatmapAttrsToList
|
# in flatmapAttrsToList
|
||||||
(host: hostOpts:
|
# (host: hostOpts:
|
||||||
(a-record host hostOpts) ++
|
# (a-record host hostOpts) ++
|
||||||
(aaaa-record host hostOpts) ++
|
# (aaaa-record host hostOpts) ++
|
||||||
(description-record host hostOpts))
|
# (description-record host hostOpts))
|
||||||
ns-hosts;
|
# ns-hosts;
|
||||||
|
|
||||||
|
|
||||||
srvRecordPair = domain: protocol: service: record: {
|
srvRecordPair = domain: protocol: service: record: {
|
||||||
@ -97,63 +146,32 @@ let
|
|||||||
$ORIGIN ${dom}.
|
$ORIGIN ${dom}.
|
||||||
$TTL ${zone.default-ttl}
|
$TTL ${zone.default-ttl}
|
||||||
|
|
||||||
###
|
|
||||||
# Default Host
|
|
||||||
###
|
|
||||||
${optionalString (zone.default-host != null)
|
${optionalString (zone.default-host != null)
|
||||||
"@ IN A ${zone.default-host}"}
|
"@ IN A ${zone.default-host}"}
|
||||||
|
|
||||||
###
|
|
||||||
# MX Records
|
|
||||||
###
|
|
||||||
${join-lines (mxRecords zone.mx)}
|
${join-lines (mxRecords zone.mx)}
|
||||||
|
|
||||||
# dmarc
|
|
||||||
${dmarcRecord zone.dmarc-report-address}
|
${dmarcRecord zone.dmarc-report-address}
|
||||||
|
|
||||||
###
|
|
||||||
# Kerberos Realm
|
|
||||||
###
|
|
||||||
${optionalString (zone.gssapi-realm != null)
|
${optionalString (zone.gssapi-realm != null)
|
||||||
''_kerberos IN TXT "${zone.gssapi-realm}"''}
|
''_kerberos IN TXT "${zone.gssapi-realm}"''}
|
||||||
|
|
||||||
###
|
|
||||||
# Nameservers
|
|
||||||
###
|
|
||||||
${join-lines (nsRecords dom zone.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)}
|
${join-lines (mapAttrsToList makeSrvProtocolRecords zone.srv-records)}
|
||||||
|
|
||||||
###
|
$TTL ${zone.host-record-ttl}
|
||||||
# Host Records
|
|
||||||
###
|
|
||||||
${join-lines (mapAttrsToList hostRecords zone.hosts)}
|
${join-lines (mapAttrsToList hostRecords zone.hosts)}
|
||||||
|
|
||||||
###
|
|
||||||
# CNAMEs
|
|
||||||
###
|
|
||||||
${join-lines (mapAttrsToList cnameRecord zone.aliases)}
|
${join-lines (mapAttrsToList cnameRecord zone.aliases)}
|
||||||
|
|
||||||
###
|
|
||||||
# Verbatim Records
|
|
||||||
###
|
|
||||||
${join-lines zone.verbatim-dns-records}
|
${join-lines zone.verbatim-dns-records}
|
||||||
|
|
||||||
###
|
|
||||||
# Subdomains of ${dom}
|
|
||||||
###
|
|
||||||
${join-lines (mapAttrsToList
|
${join-lines (mapAttrsToList
|
||||||
(subdom: subdomCfg: subdomain-record "${subdom}.${dom}" subdomCfg)
|
(subdom: subdomCfg: domain-record "${subdom}.${dom}" subdomCfg)
|
||||||
zone.subdomains)}
|
zone.subdomains)}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
@ -173,17 +191,18 @@ in rec {
|
|||||||
(service: records: map (srvRecordPair domain protocol service) records) services)
|
(service: records: map (srvRecordPair domain protocol service) records) services)
|
||||||
srvRecords);
|
srvRecords);
|
||||||
|
|
||||||
zoneToZonefile = timestamp: dom: zone: ''
|
zoneToZonefile = timestamp: dom: zone:
|
||||||
$ORIGIN ${dom}.
|
remove-blank-lines (format-zone ''
|
||||||
$TTL ${zone.default-ttl}
|
$ORIGIN ${dom}.
|
||||||
|
$TTL ${zone.default-ttl}
|
||||||
|
|
||||||
@ IN SOA ns1.${dom}. hostmaster.${dom}. (
|
@ IN SOA ns1.${dom}. hostmaster.${dom}. (
|
||||||
${toString timestamp}
|
${toString timestamp}
|
||||||
30m
|
30m
|
||||||
2m
|
2m
|
||||||
3w
|
3w
|
||||||
5m)
|
5m)
|
||||||
|
|
||||||
${domain-record dom zone}
|
${domain-record dom zone}
|
||||||
'';
|
'');
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,8 @@ let
|
|||||||
import-by-basename = path:
|
import-by-basename = path:
|
||||||
mapAttrs (attr: attr-file: import attr-file)
|
mapAttrs (attr: attr-file: import attr-file)
|
||||||
(basename-to-file-map path);
|
(basename-to-file-map path);
|
||||||
|
|
||||||
|
list-nix-files = nix-files;
|
||||||
in {
|
in {
|
||||||
inherit basename-to-file-map import-by-basename;
|
inherit basename-to-file-map import-by-basename list-nix-files;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
{ lib, ... }:
|
{ lib, ... }:
|
||||||
|
|
||||||
{ hostname, ... }:
|
|
||||||
with lib;
|
with lib;
|
||||||
{
|
{
|
||||||
options = with types; {
|
options = with types; {
|
||||||
@ -23,6 +22,13 @@ with lib;
|
|||||||
default = null;
|
default = null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
authoritative-hostname = mkOption {
|
||||||
|
type = nullOr str;
|
||||||
|
description =
|
||||||
|
"The 'real' hostname of this host, i.e. CNAME. Prefer aliases!";
|
||||||
|
default = null;
|
||||||
|
};
|
||||||
|
|
||||||
description = mkOption {
|
description = mkOption {
|
||||||
type = nullOr str;
|
type = nullOr str;
|
||||||
description = "Description of the host.";
|
description = "Description of the host.";
|
||||||
|
Loading…
x
Reference in New Issue
Block a user