Merge pull request #31724 from pngwjpgh/feat/nsd/dnssec

Automatic DNSSEC signatures & key schedule for nsd
This commit is contained in:
Matthew Justin Bauer 2018-04-21 15:15:03 -05:00 committed by GitHub
commit 55a7e45529
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 141 additions and 10 deletions

View File

@ -251,6 +251,46 @@ let
''; '';
}; };
dnssec = mkEnableOption "DNSSEC";
dnssecPolicy = {
algorithm = mkOption {
type = types.str;
default = "RSASHA256";
description = "Which algorithm to use for DNSSEC";
};
keyttl = mkOption {
type = types.str;
default = "1h";
description = "TTL for dnssec records";
};
coverage = mkOption {
type = types.str;
default = "1y";
description = ''
The length of time to ensure that keys will be correct; no action will be taken to create new keys to be activated after this time.
'';
};
zsk = mkOption {
type = keyPolicy;
default = { keySize = 2048;
prePublish = "1w";
postPublish = "1w";
rollPeriod = "1mo";
};
description = "Key policy for zone signing keys";
};
ksk = mkOption {
type = keyPolicy;
default = { keySize = 4096;
prePublish = "1mo";
postPublish = "1mo";
rollPeriod = "0";
};
description = "Key policy for key signing keys";
};
};
maxRefreshSecs = mkOption { maxRefreshSecs = mkOption {
type = types.nullOr types.int; type = types.nullOr types.int;
default = null; default = null;
@ -367,10 +407,61 @@ let
and stats_noreset. and stats_noreset.
''; '';
}; };
}; };
}; };
keyPolicy = types.submodule {
options = {
keySize = mkOption {
type = types.int;
description = "Key size in bits";
};
prePublish = mkOption {
type = types.str;
description = "How long in advance to publish new keys";
};
postPublish = mkOption {
type = types.str;
description = "How long after deactivation to keep a key in the zone";
};
rollPeriod = mkOption {
type = types.str;
description = "How frequently to change keys";
};
};
};
dnssecZones = (filterAttrs (n: v: if v ? dnssec then v.dnssec else false) zoneConfigs);
dnssec = length (attrNames dnssecZones) != 0;
signZones = optionalString dnssec ''
mkdir -p ${stateDir}/dnssec
chown ${username}:${username} ${stateDir}/dnssec
chmod 0600 ${stateDir}/dnssec
${concatStrings (mapAttrsToList signZone dnssecZones)}
'';
signZone = name: zone: ''
${pkgs.bind}/bin/dnssec-keymgr -g ${pkgs.bind}/bin/dnssec-keygen -s ${pkgs.bind}/bin/dnssec-settime -K ${stateDir}/dnssec -c ${policyFile name zone.dnssecPolicy} ${name}
${pkgs.bind}/bin/dnssec-signzone -S -K ${stateDir}/dnssec -o ${name} -O full -N date ${stateDir}/zones/${name}
${nsdPkg}/sbin/nsd-checkzone ${name} ${stateDir}/zones/${name}.signed && mv -v ${stateDir}/zones/${name}.signed ${stateDir}/zones/${name}
'';
policyFile = name: policy: pkgs.writeText "${name}.policy" ''
zone ${name} {
algorithm ${policy.algorithm};
key-size zsk ${toString policy.zsk.keySize};
key-size ksk ${toString policy.ksk.keySize};
keyttl ${policy.keyttl};
pre-publish zsk ${policy.zsk.prePublish};
pre-publish ksk ${policy.ksk.prePublish};
post-publish zsk ${policy.zsk.postPublish};
post-publish ksk ${policy.ksk.postPublish};
roll-period zsk ${policy.zsk.rollPeriod};
roll-period ksk ${policy.ksk.rollPeriod};
coverage ${policy.coverage};
};
'';
in in
{ {
# options are ordered alphanumerically # options are ordered alphanumerically
@ -380,6 +471,14 @@ in
bind8Stats = mkEnableOption "BIND8 like statistics"; bind8Stats = mkEnableOption "BIND8 like statistics";
dnssecInterval = mkOption {
type = types.str;
default = "1h";
description = ''
How often to check whether dnssec key rollover is required
'';
};
extraConfig = mkOption { extraConfig = mkOption {
type = types.str; type = types.str;
default = ""; default = "";
@ -741,7 +840,6 @@ in
}; };
zones = mkOption { zones = mkOption {
type = types.attrsOf zoneOptions; type = types.attrsOf zoneOptions;
default = {}; default = {};
@ -785,7 +883,6 @@ in
serverGroup1. serverGroup1.
''; '';
}; };
}; };
config = mkIf cfg.enable { config = mkIf cfg.enable {
@ -832,9 +929,9 @@ in
mkdir -m 0700 -p "${stateDir}/var" mkdir -m 0700 -p "${stateDir}/var"
cat > "${stateDir}/don't touch anything in here" << EOF cat > "${stateDir}/don't touch anything in here" << EOF
Everything in this directory except NSD's state in var is Everything in this directory except NSD's state in var and dnssec
automatically generated and will be purged and redeployed is automatically generated and will be purged and redeployed by
by the nsd.service pre-start script. the nsd.service pre-start script.
EOF EOF
chown ${username}:${username} -R "${stateDir}/private" chown ${username}:${username} -R "${stateDir}/private"
@ -848,6 +945,34 @@ in
''; '';
}; };
nixpkgs.config = mkIf dnssec {
bind.enablePython = true;
};
systemd.timers."nsd-dnssec" = mkIf dnssec {
description = "Automatic DNSSEC key rollover";
wantedBy = [ "nsd.service" ];
timerConfig = {
OnActiveSec = cfg.dnssecInterval;
OnUnitActiveSec = cfg.dnssecInterval;
};
};
systemd.services."nsd-dnssec" = mkIf dnssec {
description = "DNSSEC key rollover";
wantedBy = [ "nsd.service" ];
before = [ "nsd.service" ];
script = signZones;
postStop = ''
${pkgs.systemd}/bin/systemctl kill -s SIGHUP nsd.service
'';
};
}; };
meta.maintainers = with lib.maintainers; [ hrdinka ]; meta.maintainers = with lib.maintainers; [ hrdinka ];

View File

@ -1,8 +1,10 @@
{ stdenv, lib, fetchurl, openssl, libtool, perl, libxml2 { stdenv, lib, fetchurl, openssl, libtool, perl, libxml2
, enablePython ? false, python3 ? null
, enableSeccomp ? false, libseccomp ? null, buildPackages , enableSeccomp ? false, libseccomp ? null, buildPackages
}: }:
assert enableSeccomp -> libseccomp != null; assert enableSeccomp -> libseccomp != null;
assert enablePython -> python3 != null;
let version = "9.12.1"; in let version = "9.12.1"; in
@ -20,8 +22,9 @@ stdenv.mkDerivation rec {
stdenv.lib.optional stdenv.isDarwin ./darwin-openssl-linking-fix.patch; stdenv.lib.optional stdenv.isDarwin ./darwin-openssl-linking-fix.patch;
nativeBuildInputs = [ perl ]; nativeBuildInputs = [ perl ];
buildInputs = [ openssl libtool libxml2 ] ++ buildInputs = [ openssl libtool libxml2 ]
stdenv.lib.optional enableSeccomp libseccomp; ++ lib.optional enableSeccomp libseccomp
++ lib.optional enablePython python3;
STD_CDEFINES = [ "-DDIG_SIGCHASE=1" ]; # support +sigchase STD_CDEFINES = [ "-DDIG_SIGCHASE=1" ]; # support +sigchase
@ -32,6 +35,7 @@ stdenv.mkDerivation rec {
"--with-libtool" "--with-libtool"
"--with-libxml2=${libxml2.dev}" "--with-libxml2=${libxml2.dev}"
"--with-openssl=${openssl.dev}" "--with-openssl=${openssl.dev}"
(if enablePython then "--with-python" else "--without-python")
"--without-atf" "--without-atf"
"--without-dlopen" "--without-dlopen"
"--without-docbook-xsl" "--without-docbook-xsl"
@ -41,7 +45,6 @@ stdenv.mkDerivation rec {
"--without-lmdb" "--without-lmdb"
"--without-pkcs11" "--without-pkcs11"
"--without-purify" "--without-purify"
"--without-python"
"--with-randomdev=/dev/random" "--with-randomdev=/dev/random"
"--with-ecdsa" "--with-ecdsa"
"--with-gost" "--with-gost"

View File

@ -12262,7 +12262,10 @@ with pkgs;
bftpd = callPackage ../servers/ftp/bftpd {}; bftpd = callPackage ../servers/ftp/bftpd {};
bind = callPackage ../servers/dns/bind { }; bind = callPackage ../servers/dns/bind {
enablePython = config.bind.enablePython or false;
python3 = python3.withPackages (ps: with ps; [ ply ]);
};
dnsutils = bind.dnsutils; dnsutils = bind.dnsutils;
inherit (callPackages ../servers/bird { }) inherit (callPackages ../servers/bird { })