1import ../make-test-python.nix (
2 { pkgs, ... }:
3 {
4 name = "kerberos_server-heimdal";
5
6 nodes = {
7 server =
8 { config, pkgs, ... }:
9 {
10 imports = [ ../common/user-account.nix ];
11
12 users.users.alice.extraGroups = [ "wheel" ];
13
14 services.getty.autologinUser = "alice";
15
16 virtualisation.vlans = [ 1 ];
17
18 time.timeZone = "Etc/UTC";
19
20 networking = {
21 domain = "foo.bar";
22 useDHCP = false;
23 firewall.enable = false;
24 hosts."10.0.0.1" = [ "server.foo.bar" ];
25 hosts."10.0.0.2" = [ "client.foo.bar" ];
26 };
27
28 systemd.network.networks."01-eth1" = {
29 name = "eth1";
30 networkConfig.Address = "10.0.0.1/24";
31 };
32
33 security.krb5 = {
34 enable = true;
35 package = pkgs.heimdal;
36 settings = {
37 libdefaults.default_realm = "FOO.BAR";
38
39 # Enable extra debug output
40 logging = {
41 admin_server = "SYSLOG:DEBUG:AUTH";
42 default = "SYSLOG:DEBUG:AUTH";
43 kdc = "SYSLOG:DEBUG:AUTH";
44 };
45
46 realms = {
47 "FOO.BAR" = {
48 admin_server = "server.foo.bar";
49 kpasswd_server = "server.foo.bar";
50 kdc = [ "server.foo.bar" ];
51 };
52 };
53 };
54 };
55
56 services.kerberos_server = {
57 enable = true;
58 settings.realms = {
59 "FOO.BAR" = {
60 acl = [
61 {
62 principal = "kadmin/admin@FOO.BAR";
63 access = "all";
64 }
65 {
66 principal = "alice/admin@FOO.BAR";
67 access = [
68 "add"
69 "cpw"
70 "delete"
71 "get"
72 "list"
73 "modify"
74 ];
75 }
76 ];
77 };
78 };
79 };
80 };
81
82 client =
83 { config, pkgs, ... }:
84 {
85 imports = [ ../common/user-account.nix ];
86
87 users.users.alice.extraGroups = [ "wheel" ];
88
89 services.getty.autologinUser = "alice";
90
91 virtualisation.vlans = [ 1 ];
92
93 time.timeZone = "Etc/UTC";
94
95 networking = {
96 domain = "foo.bar";
97 useDHCP = false;
98 hosts."10.0.0.1" = [ "server.foo.bar" ];
99 hosts."10.0.0.2" = [ "client.foo.bar" ];
100 };
101
102 systemd.network.networks."01-eth1" = {
103 name = "eth1";
104 networkConfig.Address = "10.0.0.2/24";
105 };
106
107 security.krb5 = {
108 enable = true;
109 package = pkgs.heimdal;
110 settings = {
111 libdefaults.default_realm = "FOO.BAR";
112
113 logging = {
114 admin_server = "SYSLOG:DEBUG:AUTH";
115 default = "SYSLOG:DEBUG:AUTH";
116 kdc = "SYSLOG:DEBUG:AUTH";
117 };
118
119 realms = {
120 "FOO.BAR" = {
121 admin_server = "server.foo.bar";
122 kpasswd_server = "server.foo.bar";
123 kdc = [ "server.foo.bar" ];
124 };
125 };
126 };
127 };
128 };
129 };
130
131 testScript =
132 { nodes, ... }:
133 ''
134 import string
135 import random
136 random.seed(0)
137
138 start_all()
139
140 with subtest("Server: initialize realm"):
141 # for unit in ["kadmind.service", "kdc.socket", "kpasswdd.socket"]:
142 for unit in ["kadmind.service", "kdc.service", "kpasswdd.service"]:
143 server.wait_for_unit(unit)
144
145 server.succeed("kadmin -l init --realm-max-ticket-life='8 day' --realm-max-renewable-life='10 day' FOO.BAR")
146
147 for unit in ["kadmind.service", "kdc.service", "kpasswdd.service"]:
148 server.systemctl(f"restart {unit}")
149
150 alice_krb_pw = "alice_hunter2"
151 alice_old_krb_pw = ""
152 alice_krb_admin_pw = "alice_admin_hunter2"
153
154 def random_password():
155 password_chars = string.ascii_letters + string.digits + string.punctuation.replace('"', "")
156 return "".join(random.choice(password_chars) for _ in range(16))
157
158 with subtest("Server: initialize user principals and keytabs"):
159 server.succeed(f'kadmin -l add --password="{alice_krb_admin_pw}" --use-defaults alice/admin')
160 server.succeed("kadmin -l ext_keytab --keytab=admin.keytab alice/admin")
161
162 server.succeed(f'kadmin -p alice/admin -K admin.keytab add --password="{alice_krb_pw}" --use-defaults alice')
163 server.succeed("kadmin -l ext_keytab --keytab=alice.keytab alice")
164
165 server.wait_for_unit("getty@tty1.service")
166 server.wait_until_succeeds("pgrep -f 'agetty.*tty1'")
167 server.wait_for_unit("default.target")
168
169 with subtest("Server: initialize host principal with keytab"):
170 server.send_chars("sudo ktutil get -p alice/admin host/server.foo.bar\n")
171 server.wait_until_tty_matches("1", "password for alice:")
172 server.send_chars("${nodes.server.config.users.users.alice.password}\n")
173 server.wait_until_tty_matches("1", "alice/admin@FOO.BAR's Password:")
174 server.send_chars(f'{alice_krb_admin_pw}\n')
175 server.wait_for_file("/etc/krb5.keytab")
176
177 ktutil_list = server.succeed("sudo ktutil list")
178 if not "host/server.foo.bar" in ktutil_list:
179 exit(1)
180
181 server.send_chars("clear\n")
182
183 client.systemctl("start network-online.target")
184 client.wait_for_unit("network-online.target")
185 client.wait_for_unit("getty@tty1.service")
186 client.wait_until_succeeds("pgrep -f 'agetty.*tty1'")
187 client.wait_for_unit("default.target")
188
189 with subtest("Client: initialize host principal with keytab"):
190 client.succeed(
191 f'echo "{alice_krb_admin_pw}" > pw.txt',
192 "kinit -p --password-file=pw.txt alice/admin",
193 )
194
195 client.send_chars("sudo ktutil get -p alice/admin host/client.foo.bar\n")
196 client.wait_until_tty_matches("1", "password for alice:")
197 client.send_chars("${nodes.client.config.users.users.alice.password}\n")
198 client.wait_until_tty_matches("1", "alice/admin@FOO.BAR's Password:")
199 client.send_chars(f"{alice_krb_admin_pw}\n")
200 client.wait_for_file("/etc/krb5.keytab")
201
202 ktutil_list = client.succeed("sudo ktutil list")
203 if not "host/client.foo.bar" in ktutil_list:
204 exit(1)
205
206 client.send_chars("clear\n")
207
208 with subtest("Client: kinit alice"):
209 client.succeed(
210 f"echo '{alice_krb_pw}' > pw.txt",
211 "kinit -p --password-file=pw.txt alice",
212 )
213 tickets = client.succeed("klist")
214 assert "Principal: alice@FOO.BAR" in tickets
215 client.send_chars("clear\n")
216
217 with subtest("Client: kpasswd alice"):
218 alice_old_krb_pw = alice_krb_pw
219 alice_krb_pw = random_password()
220 client.send_chars("kpasswd\n")
221 client.wait_until_tty_matches("1", "alice@FOO.BAR's Password:")
222 client.send_chars(f"{alice_old_krb_pw}\n", 0.1)
223 client.wait_until_tty_matches("1", "New password:")
224 client.send_chars(f"{alice_krb_pw}\n", 0.1)
225 client.wait_until_tty_matches("1", "Verify password - New password:")
226 client.send_chars(f"{alice_krb_pw}\n", 0.1)
227
228 client.wait_until_tty_matches("1", "Success : Password changed")
229
230 client.send_chars("clear\n")
231
232 with subtest("Server: kinit alice"):
233 server.succeed(
234 "echo 'alice_pw_2' > pw.txt"
235 "kinit -p --password-file=pw.txt alice",
236 )
237 tickets = client.succeed("klist")
238 assert "Principal: alice@FOO.BAR" in tickets
239 server.send_chars("clear\n")
240
241 with subtest("Server: kpasswd alice"):
242 alice_old_krb_pw = alice_krb_pw
243 alice_krb_pw = random_password()
244 server.send_chars("kpasswd\n")
245 server.wait_until_tty_matches("1", "alice@FOO.BAR's Password:")
246 server.send_chars(f"{alice_old_krb_pw}\n", 0.1)
247 server.wait_until_tty_matches("1", "New password:")
248 server.send_chars(f"{alice_krb_pw}\n", 0.1)
249 server.wait_until_tty_matches("1", "Verify password - New password:")
250 server.send_chars(f"{alice_krb_pw}\n", 0.1)
251
252 server.wait_until_tty_matches("1", "Success : Password changed")
253
254 server.send_chars("clear\n")
255 '';
256
257 meta.maintainers = pkgs.heimdal.meta.maintainers;
258 }
259)