zfs_unstable: 2.3.0-rc3 -> 2.3.0-rc4 (#365045)
[NixPkgs.git] / nixos / modules / services / networking / nbd.nix
blob1fcbc1969543fcd907cf2e95f99cb82a9cf46329
2   config,
3   lib,
4   pkgs,
5   ...
6 }:
8 let
9   inherit (lib)
10     mkIf
11     mkOption
12     types
13     optionalAttrs
14     ;
15   inherit (lib.types)
16     nullOr
17     listOf
18     str
19     attrsOf
20     submodule
21     ;
22   cfg = config.services.nbd;
23   iniFields =
24     with types;
25     attrsOf (oneOf [
26       bool
27       int
28       float
29       str
30     ]);
31   # The `[generic]` section must come before all the others in the
32   # config file.  This means we can't just dump an attrset to INI
33   # because that sorts the sections by name.  Instead, we serialize it
34   # on its own first.
35   genericSection = {
36     generic = (
37       cfg.server.extraOptions
38       // {
39         user = "root";
40         group = "root";
41         port = cfg.server.listenPort;
42       }
43       // (optionalAttrs (cfg.server.listenAddress != null) {
44         listenaddr = cfg.server.listenAddress;
45       })
46     );
47   };
48   exportSections = lib.mapAttrs (
49     _:
50     {
51       path,
52       allowAddresses,
53       extraOptions,
54     }:
55     extraOptions
56     // {
57       exportname = path;
58     }
59     // (optionalAttrs (allowAddresses != null) {
60       authfile = pkgs.writeText "authfile" (lib.concatStringsSep "\n" allowAddresses);
61     })
62   ) cfg.server.exports;
63   serverConfig = pkgs.writeText "nbd-server-config" ''
64     ${lib.generators.toINI { } genericSection}
65     ${lib.generators.toINI { } exportSections}
66   '';
67   splitLists = lib.partition (path: lib.hasPrefix "/dev/" path) (
68     lib.mapAttrsToList (_: { path, ... }: path) cfg.server.exports
69   );
70   allowedDevices = splitLists.right;
71   boundPaths = splitLists.wrong;
74   options = {
75     services.nbd = {
76       server = {
77         enable = lib.mkEnableOption "the Network Block Device (nbd) server";
79         listenPort = mkOption {
80           type = types.port;
81           default = 10809;
82           description = "Port to listen on. The port is NOT automatically opened in the firewall.";
83         };
85         extraOptions = mkOption {
86           type = iniFields;
87           default = {
88             allowlist = false;
89           };
90           description = ''
91             Extra options for the server. See
92             {manpage}`nbd-server(5)`.
93           '';
94         };
96         exports = mkOption {
97           description = "Files or block devices to make available over the network.";
98           default = { };
99           type = attrsOf (submodule {
100             options = {
101               path = mkOption {
102                 type = str;
103                 description = "File or block device to export.";
104                 example = "/dev/sdb1";
105               };
107               allowAddresses = mkOption {
108                 type = nullOr (listOf str);
109                 default = null;
110                 example = [
111                   "10.10.0.0/24"
112                   "127.0.0.1"
113                 ];
114                 description = "IPs and subnets that are authorized to connect for this device. If not specified, the server will allow all connections.";
115               };
117               extraOptions = mkOption {
118                 type = iniFields;
119                 default = {
120                   flush = true;
121                   fua = true;
122                 };
123                 description = ''
124                   Extra options for this export. See
125                   {manpage}`nbd-server(5)`.
126                 '';
127               };
128             };
129           });
130         };
132         listenAddress = mkOption {
133           type = nullOr str;
134           description = "Address to listen on. If not specified, the server will listen on all interfaces.";
135           default = null;
136           example = "10.10.0.1";
137         };
138       };
139     };
140   };
142   config = mkIf cfg.server.enable {
143     assertions = [
144       {
145         assertion = !(cfg.server.exports ? "generic");
146         message = "services.nbd.server exports must not be named 'generic'";
147       }
148     ];
150     boot.kernelModules = [ "nbd" ];
152     systemd.services.nbd-server = {
153       wants = [ "network-online.target" ];
154       after = [ "network-online.target" ];
155       before = [ "multi-user.target" ];
156       wantedBy = [ "multi-user.target" ];
157       serviceConfig = {
158         ExecStart = "${pkgs.nbd}/bin/nbd-server -C ${serverConfig}";
159         Type = "forking";
161         DeviceAllow = map (path: "${path} rw") allowedDevices;
162         BindPaths = boundPaths;
164         CapabilityBoundingSet = "";
165         DevicePolicy = "closed";
166         LockPersonality = true;
167         MemoryDenyWriteExecute = true;
168         NoNewPrivileges = true;
169         PrivateDevices = false;
170         PrivateMounts = true;
171         PrivateTmp = true;
172         PrivateUsers = true;
173         ProcSubset = "pid";
174         ProtectClock = true;
175         ProtectControlGroups = true;
176         ProtectHome = true;
177         ProtectHostname = true;
178         ProtectKernelLogs = true;
179         ProtectKernelModules = true;
180         ProtectKernelTunables = true;
181         ProtectProc = "noaccess";
182         ProtectSystem = "strict";
183         RestrictAddressFamilies = "AF_INET AF_INET6";
184         RestrictNamespaces = true;
185         RestrictRealtime = true;
186         RestrictSUIDSGID = true;
187         UMask = "0077";
188       };
189     };
190   };