1import ../make-test-python.nix ({ pkgs, lib, ... }:
2
3let
4 krb5 =
5 { enable = true;
6 domain_realm."nfs.test" = "NFS.TEST";
7 libdefaults.default_realm = "NFS.TEST";
8 realms."NFS.TEST" =
9 { admin_server = "server.nfs.test";
10 kdc = "server.nfs.test";
11 };
12 };
13
14 hosts =
15 ''
16 192.168.1.1 client.nfs.test
17 192.168.1.2 server.nfs.test
18 '';
19
20 users = {
21 users.alice = {
22 isNormalUser = true;
23 name = "alice";
24 uid = 1000;
25 };
26 };
27
28in
29
30{
31 name = "nfsv4-with-kerberos";
32
33 nodes = {
34 client = { lib, ... }:
35 { inherit krb5 users;
36
37 networking.extraHosts = hosts;
38 networking.domain = "nfs.test";
39 networking.hostName = "client";
40
41 virtualisation.fileSystems =
42 { "/data" = {
43 device = "server.nfs.test:/";
44 fsType = "nfs";
45 options = [ "nfsvers=4" "sec=krb5p" "noauto" ];
46 };
47 };
48 };
49
50 server = { lib, ...}:
51 { inherit krb5 users;
52
53 networking.extraHosts = hosts;
54 networking.domain = "nfs.test";
55 networking.hostName = "server";
56
57 networking.firewall.allowedTCPPorts = [
58 111 # rpc
59 2049 # nfs
60 88 # kerberos
61 749 # kerberos admin
62 ];
63
64 services.kerberos_server.enable = true;
65 services.kerberos_server.realms =
66 { "NFS.TEST".acl =
67 [ { access = "all"; principal = "admin/admin"; } ];
68 };
69
70 services.nfs.server.enable = true;
71 services.nfs.server.createMountPoints = true;
72 services.nfs.server.exports =
73 ''
74 /data *(rw,no_root_squash,fsid=0,sec=krb5p)
75 '';
76 };
77 };
78
79 testScript =
80 ''
81 server.succeed("mkdir -p /data/alice")
82 server.succeed("chown alice:users /data/alice")
83
84 # set up kerberos database
85 server.succeed(
86 "kdb5_util create -s -r NFS.TEST -P master_key",
87 "systemctl restart kadmind.service kdc.service",
88 )
89 server.wait_for_unit("kadmind.service")
90 server.wait_for_unit("kdc.service")
91
92 # create principals
93 server.succeed(
94 "kadmin.local add_principal -randkey nfs/server.nfs.test",
95 "kadmin.local add_principal -randkey nfs/client.nfs.test",
96 "kadmin.local add_principal -pw admin_pw admin/admin",
97 "kadmin.local add_principal -pw alice_pw alice",
98 )
99
100 # add principals to server keytab
101 server.succeed("kadmin.local ktadd nfs/server.nfs.test")
102 server.succeed("systemctl start rpc-gssd.service rpc-svcgssd.service")
103 server.wait_for_unit("rpc-gssd.service")
104 server.wait_for_unit("rpc-svcgssd.service")
105
106 client.wait_for_unit("network-online.target")
107
108 # add principals to client keytab
109 client.succeed("echo admin_pw | kadmin -p admin/admin ktadd nfs/client.nfs.test")
110 client.succeed("systemctl start rpc-gssd.service")
111 client.wait_for_unit("rpc-gssd.service")
112
113 with subtest("nfs share mounts"):
114 client.succeed("systemctl restart data.mount")
115 client.wait_for_unit("data.mount")
116
117 with subtest("permissions on nfs share are enforced"):
118 client.fail("su alice -c 'ls /data'")
119 client.succeed("su alice -c 'echo alice_pw | kinit'")
120 client.succeed("su alice -c 'ls /data'")
121
122 client.fail("su alice -c 'echo bla >> /data/foo'")
123 client.succeed("su alice -c 'echo bla >> /data/alice/foo'")
124 server.succeed("test -e /data/alice/foo")
125
126 with subtest("uids/gids are mapped correctly on nfs share"):
127 ids = client.succeed("stat -c '%U %G' /data/alice").split()
128 expected = ["alice", "users"]
129 assert ids == expected, f"ids incorrect: got {ids} expected {expected}"
130 '';
131})