1{ config, lib, pkgs, ... }:
2
3with lib;
4
5let
6 cfg = config.services.knot;
7
8 configFile = pkgs.writeTextFile {
9 name = "knot.conf";
10 text = (concatMapStringsSep "\n" (file: "include: ${file}") cfg.keyFiles) + "\n" +
11 cfg.extraConfig;
12 checkPhase = lib.optionalString (cfg.keyFiles == []) ''
13 ${cfg.package}/bin/knotc --config=$out conf-check
14 '';
15 };
16
17 socketFile = "/run/knot/knot.sock";
18
19 knot-cli-wrappers = pkgs.stdenv.mkDerivation {
20 name = "knot-cli-wrappers";
21 buildInputs = [ pkgs.makeWrapper ];
22 buildCommand = ''
23 mkdir -p $out/bin
24 makeWrapper ${cfg.package}/bin/knotc "$out/bin/knotc" \
25 --add-flags "--config=${configFile}" \
26 --add-flags "--socket=${socketFile}"
27 makeWrapper ${cfg.package}/bin/keymgr "$out/bin/keymgr" \
28 --add-flags "--config=${configFile}"
29 for executable in kdig khost kjournalprint knsec3hash knsupdate kzonecheck
30 do
31 ln -s "${cfg.package}/bin/$executable" "$out/bin/$executable"
32 done
33 mkdir -p "$out/share"
34 ln -s '${cfg.package}/share/man' "$out/share/"
35 '';
36 };
37in {
38 options = {
39 services.knot = {
40 enable = mkEnableOption "Knot authoritative-only DNS server";
41
42 extraArgs = mkOption {
43 type = types.listOf types.str;
44 default = [];
45 description = ''
46 List of additional command line paramters for knotd
47 '';
48 };
49
50 keyFiles = mkOption {
51 type = types.listOf types.path;
52 default = [];
53 description = ''
54 A list of files containing additional configuration
55 to be included using the include directive. This option
56 allows to include configuration like TSIG keys without
57 exposing them to the nix store readable to any process.
58 Note that using this option will also disable configuration
59 checks at build time.
60 '';
61 };
62
63 extraConfig = mkOption {
64 type = types.lines;
65 default = "";
66 description = ''
67 Extra lines to be added verbatim to knot.conf
68 '';
69 };
70
71 package = mkOption {
72 type = types.package;
73 default = pkgs.knot-dns;
74 defaultText = "pkgs.knot-dns";
75 description = ''
76 Which Knot DNS package to use
77 '';
78 };
79 };
80 };
81
82 config = mkIf config.services.knot.enable {
83 users.users.knot = {
84 isSystemUser = true;
85 group = "knot";
86 description = "Knot daemon user";
87 };
88
89 users.groups.knot.gid = null;
90 systemd.services.knot = {
91 unitConfig.Documentation = "man:knotd(8) man:knot.conf(5) man:knotc(8) https://www.knot-dns.cz/docs/${cfg.package.version}/html/";
92 description = cfg.package.meta.description;
93 wantedBy = [ "multi-user.target" ];
94 wants = [ "network.target" ];
95 after = ["network.target" ];
96
97 serviceConfig = {
98 Type = "notify";
99 ExecStart = "${cfg.package}/bin/knotd --config=${configFile} --socket=${socketFile} ${concatStringsSep " " cfg.extraArgs}";
100 ExecReload = "${knot-cli-wrappers}/bin/knotc reload";
101 CapabilityBoundingSet = "CAP_NET_BIND_SERVICE CAP_SETPCAP";
102 AmbientCapabilities = "CAP_NET_BIND_SERVICE CAP_SETPCAP";
103 NoNewPrivileges = true;
104 User = "knot";
105 RuntimeDirectory = "knot";
106 StateDirectory = "knot";
107 StateDirectoryMode = "0700";
108 PrivateDevices = true;
109 RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6";
110 SystemCallArchitectures = "native";
111 Restart = "on-abort";
112 };
113 };
114
115 environment.systemPackages = [ knot-cli-wrappers ];
116 };
117}