nixos-config/lib/fudo/backplane/dns.nix
2021-11-05 07:06:08 -07:00

265 lines
7.8 KiB
Nix

{ config, pkgs, lib, ... }:
with lib;
let
cfg = config.fudo.backplane.dns;
powerdns-conf-dir = "${cfg.powerdns.home}/conf.d";
backplaneOpts = { ... }: {
options = {
host = mkOption {
type = types.str;
description = "Hostname of the backplane jabber server.";
};
role = mkOption {
type = types.str;
description = "Backplane XMPP role name for the DNS server.";
default = "service-dns";
};
password-file = mkOption {
type = types.str;
description = "File containing XMPP password for backplane role.";
};
database = mkOption {
type = with types; submodule databaseOpts;
description = "Database settings for backplane server.";
};
cl-wrapper-package = mkOption {
type = types.package;
description = "Common Lisp wrapper package to use.";
default = pkgs.lispPackages.clwrapper;
};
};
};
databaseOpts = { ... }: {
options = {
host = mkOption {
type = types.str;
description = "Hostname or IP of the PostgreSQL server.";
};
database = mkOption {
type = types.str;
description = "Database to use for DNS backplane.";
default = "backplane_dns";
};
username = mkOption {
type = types.str;
description = "Database user for DNS backplane.";
default = "backplane_dns";
};
password-file = mkOption {
type = types.str;
description = "File containing password for database user.";
};
};
};
in {
options.fudo.backplane.dns = with types; {
enable = mkEnableOption "Enable backplane dynamic DNS server.";
port = mkOption {
type = port;
description = "Port on which to serve authoritative DNS requests.";
default = 53;
};
listen-v4-addresses = mkOption {
type = listOf str;
description = "IPv4 addresses on which to listen for dns requests.";
default = [ "0.0.0.0" ];
};
listen-v6-addresses = mkOption {
type = listOf str;
description = "IPv6 addresses on which to listen for dns requests.";
example = [ "[abcd::1]" ];
default = [ ];
};
required-services = mkOption {
type = listOf str;
description =
"A list of services required before the DNS server can start.";
default = [ ];
};
user = mkOption {
type = str;
description = "User as which to run DNS backplane listener service.";
default = "backplane-dns";
};
group = mkOption {
type = str;
description = "Group as which to run DNS backplane listener service.";
default = "backplane-dns";
};
database = mkOption {
type = submodule databaseOpts;
description = "Database settings for the DNS server.";
};
backplane = mkOption {
type = submodule backplaneOpts;
description = "Backplane Jabber settings for the DNS server.";
};
powerdns = {
home = mkOption {
type = str;
description = "Directory at which to store powerdns configuration and state.";
default = "/run/backplane-dns/powerdns";
};
user = mkOption {
type = str;
description = "Username as which to run PowerDNS.";
default = "backplane-powerdns";
};
};
};
config = mkIf cfg.enable {
users = {
users = {
"${cfg.user}" = {
isSystemUser = true;
group = cfg.group;
createHome = true;
home = "/var/home/${cfg.user}";
};
${cfg.powerdns.user} = {
isSystemUser = true;
home = cfg.powerdns.home;
createHome = true;
};
};
groups = {
"${cfg.group}" = { members = [ cfg.user ]; };
${cfg.powerdns.user} = { members = [ cfg.powerdns.user ]; };
};
};
fudo.system.services = {
backplane-powerdns-config-generator = {
description =
"Generate postgres configuration for backplane DNS server.";
requires = cfg.required-services;
type = "oneshot";
restartIfChanged = true;
partOf = [ "backplane-dns.target" ];
readWritePaths = [ powerdns-conf-dir ];
preStart = ''
mkdir -p ${powerdns-conf-dir}
chown ${cfg.powerdns.user}:${cfg.powerdns.user} ${powerdns-conf-dir}
'';
# This builds the config in a bash script, to avoid storing the password
# in the nix store at any point
script = ''
if [ ! -d ${powerdns-conf-dir} ]; then
mkdir ${powerdns-conf-dir}
fi
TMPDIR=$(${pkgs.coreutils}/bin/mktemp -d -t pdns-XXXXXXXXXX)
TMPCONF=$TMPDIR/pdns.local.gpgsql.conf
if [ ! -f ${cfg.database.password-file} ]; then
echo "${cfg.database.password-file} does not exist!"
exit 1
fi
touch $TMPCONF
chown ${cfg.powerdns.user}:${cfg.powerdns.user} $TMPCONF
chmod go-rwx $TMPCONF
PASSWORD=$(cat ${cfg.database.password-file})
echo "launch+=gpgsql" >> $TMPCONF
echo "gpgsql-host=${cfg.database.host}" >> $TMPCONF
echo "gpgsql-dbname=${cfg.database.database}" >> $TMPCONF
echo "gpgsql-user=${cfg.database.username}" >> $TMPCONF
echo "gpgsql-password=$PASSWORD" >> $TMPCONF
echo "gpgsql-dnssec=yes" >> $TMPCONF
mv $TMPCONF ${powerdns-conf-dir}/pdns.local.gpgsql.conf
rm -rf $TMPDIR
exit 0
'';
};
backplane-dns = {
description = "Fudo DNS Backplane Server";
restartIfChanged = true;
path = with pkgs; [ backplane-dns-server ];
execStart = "launch-backplane-dns.sh";
pidFile = "/run/backplane-dns.$USERNAME.pid";
user = cfg.user;
group = cfg.group;
partOf = [ "backplane-dns.target" ];
requires = cfg.required-services ++ [ "postgresql.service" ];
environment = {
FUDO_DNS_BACKPLANE_XMPP_HOSTNAME = cfg.backplane.host;
FUDO_DNS_BACKPLANE_XMPP_USERNAME = cfg.backplane.role;
FUDO_DNS_BACKPLANE_XMPP_PASSWORD_FILE = cfg.backplane.password-file;
FUDO_DNS_BACKPLANE_DATABASE_HOSTNAME = cfg.backplane.database.host;
FUDO_DNS_BACKPLANE_DATABASE_NAME = cfg.backplane.database.database;
FUDO_DNS_BACKPLANE_DATABASE_USERNAME =
cfg.backplane.database.username;
FUDO_DNS_BACKPLANE_DATABASE_PASSWORD_FILE =
cfg.backplane.database.password-file;
CL_SOURCE_REGISTRY =
pkgs.lib.fudo.lisp.lisp-source-registry pkgs.backplane-dns-server;
};
};
};
systemd = {
targets = {
backplane-dns = {
description = "Fudo DNS backplane services.";
wantedBy = [ "multi-user.target" ];
after = cfg.required-services ++ [ "postgresql.service" ];
};
};
services = {
backplane-powerdns = let
pdns-config-dir = pkgs.writeTextDir "pdns.conf" ''
local-address=${lib.concatStringsSep ", " cfg.listen-v4-addresses}
local-ipv6=${lib.concatStringsSep ", " cfg.listen-v6-addresses}
local-port=${toString cfg.port}
launch=
include-dir=${powerdns-conf-dir}/
'';
in {
description = "Backplane PowerDNS name server";
requires = [
"postgresql.service"
"backplane-powerdns-config-generator.service"
];
after = [ "network.target" ];
path = with pkgs; [ powerdns postgresql ];
serviceConfig = {
ExecStart = "pdns_server --setuid=${cfg.powerdns.user} --setgid=${cfg.powerdns.user} --chroot=${cfg.powerdns.home} --socket-dir=/ --daemon=no --guardian=no --disable-syslog --write-pid=no --config-dir=${pdns-config-dir}";
};
};
};
};
};
}