1{ config, lib, pkgs, ... }:
2
3with lib;
4
5let
6
7 inInitrd = any (fs: fs == "nfs") config.boot.initrd.supportedFilesystems;
8
9 nfsStateDir = "/var/lib/nfs";
10
11 rpcMountpoint = "${nfsStateDir}/rpc_pipefs";
12
13 format = pkgs.formats.ini {};
14
15 idmapdConfFile = format.generate "idmapd.conf" cfg.idmapd.settings;
16 nfsConfFile = pkgs.writeText "nfs.conf" cfg.extraConfig;
17 requestKeyConfFile = pkgs.writeText "request-key.conf" ''
18 create id_resolver * * ${pkgs.nfs-utils}/bin/nfsidmap -t 600 %k %d
19 '';
20
21 cfg = config.services.nfs;
22
23in
24
25{
26 ###### interface
27
28 options = {
29 services.nfs = {
30 idmapd.settings = mkOption {
31 type = format.type;
32 default = {};
33 description = lib.mdDoc ''
34 libnfsidmap configuration. Refer to
35 <https://linux.die.net/man/5/idmapd.conf>
36 for details.
37 '';
38 example = literalExpression ''
39 {
40 Translation = {
41 GSS-Methods = "static,nsswitch";
42 };
43 Static = {
44 "root/hostname.domain.com@REALM.COM" = "root";
45 };
46 }
47 '';
48 };
49 extraConfig = mkOption {
50 type = types.lines;
51 default = "";
52 description = lib.mdDoc ''
53 Extra nfs-utils configuration.
54 '';
55 };
56 };
57 };
58
59 ###### implementation
60
61 config = mkIf (any (fs: fs == "nfs" || fs == "nfs4") config.boot.supportedFilesystems) {
62
63 services.rpcbind.enable = true;
64
65 services.nfs.idmapd.settings = {
66 General = mkMerge [
67 { Pipefs-Directory = rpcMountpoint; }
68 (mkIf (config.networking.domain != null) { Domain = config.networking.domain; })
69 ];
70 Mapping = {
71 Nobody-User = "nobody";
72 Nobody-Group = "nogroup";
73 };
74 Translation = {
75 Method = "nsswitch";
76 };
77 };
78
79 system.fsPackages = [ pkgs.nfs-utils ];
80
81 boot.initrd.kernelModules = mkIf inInitrd [ "nfs" ];
82
83 systemd.packages = [ pkgs.nfs-utils ];
84
85 environment.systemPackages = [ pkgs.keyutils ];
86
87 environment.etc = {
88 "idmapd.conf".source = idmapdConfFile;
89 "nfs.conf".source = nfsConfFile;
90 "request-key.conf".source = requestKeyConfFile;
91 };
92
93 systemd.services.nfs-blkmap =
94 { restartTriggers = [ nfsConfFile ];
95 };
96
97 systemd.targets.nfs-client =
98 { wantedBy = [ "multi-user.target" "remote-fs.target" ];
99 };
100
101 systemd.services.nfs-idmapd =
102 { restartTriggers = [ idmapdConfFile ];
103 };
104
105 systemd.services.nfs-mountd =
106 { restartTriggers = [ nfsConfFile ];
107 enable = mkDefault false;
108 };
109
110 systemd.services.nfs-server =
111 { restartTriggers = [ nfsConfFile ];
112 enable = mkDefault false;
113 };
114
115 systemd.services.auth-rpcgss-module =
116 {
117 unitConfig.ConditionPathExists = [ "" "/etc/krb5.keytab" ];
118 };
119
120 systemd.services.rpc-gssd =
121 { restartTriggers = [ nfsConfFile ];
122 unitConfig.ConditionPathExists = [ "" "/etc/krb5.keytab" ];
123 };
124
125 systemd.services.rpc-statd =
126 { restartTriggers = [ nfsConfFile ];
127
128 preStart =
129 ''
130 mkdir -p /var/lib/nfs/{sm,sm.bak}
131 '';
132 };
133
134 };
135}