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)