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 {
|
||||
|
||||
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;
|
||||
};
|
||||
};
|
||||
|
@ -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;
|
||||
|
||||
|
157
lib/lib/dns.nix
157
lib/lib/dns.nix
@ -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}
|
||||
'');
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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.";
|
||||
|
Loading…
Reference in New Issue
Block a user