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 nativeBuildInputs = [ 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 (lib.mdDoc "Knot authoritative-only DNS server");
41
42 extraArgs = mkOption {
43 type = types.listOf types.str;
44 default = [];
45 description = lib.mdDoc ''
46 List of additional command line parameters for knotd
47 '';
48 };
49
50 keyFiles = mkOption {
51 type = types.listOf types.path;
52 default = [];
53 description = lib.mdDoc ''
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 = lib.mdDoc ''
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 = literalExpression "pkgs.knot-dns";
75 description = lib.mdDoc ''
76 Which Knot DNS package to use
77 '';
78 };
79 };
80 };
81
82 config = mkIf config.services.knot.enable {
83 users.groups.knot = {};
84 users.users.knot = {
85 isSystemUser = true;
86 group = "knot";
87 description = "Knot daemon user";
88 };
89
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 User = "knot";
102 Group = "knot";
103
104 AmbientCapabilities = [
105 "CAP_NET_BIND_SERVICE"
106 ];
107 CapabilityBoundingSet = [
108 "CAP_NET_BIND_SERVICE"
109 ];
110 DeviceAllow = "";
111 DevicePolicy = "closed";
112 LockPersonality = true;
113 MemoryDenyWriteExecute = true;
114 NoNewPrivileges = true;
115 PrivateDevices = true;
116 PrivateTmp = true;
117 PrivateUsers = false; # breaks capability passing
118 ProcSubset = "pid";
119 ProtectClock = true;
120 ProtectControlGroups = true;
121 ProtectHome = true;
122 ProtectHostname = true;
123 ProtectKernelLogs = true;
124 ProtectKernelModules = true;
125 ProtectKernelTunables = true;
126 ProtectProc = "invisible";
127 ProtectSystem = "strict";
128 RemoveIPC = true;
129 Restart = "on-abort";
130 RestrictAddressFamilies = [
131 "AF_INET"
132 "AF_INET6"
133 "AF_UNIX"
134 ];
135 RestrictNamespaces = true;
136 RestrictRealtime =true;
137 RestrictSUIDSGID = true;
138 RuntimeDirectory = "knot";
139 StateDirectory = "knot";
140 StateDirectoryMode = "0700";
141 SystemCallArchitectures = "native";
142 SystemCallFilter = [
143 "@system-service"
144 "~@privileged"
145 ];
146 UMask = "0077";
147 };
148 };
149
150 environment.systemPackages = [ knot-cli-wrappers ];
151 };
152}