diff --git a/nixos/modules/services/system/kerberos/heimdal.nix b/nixos/modules/services/system/kerberos/heimdal.nix index 4c1df2088ae3..6daa86e79aae 100644 --- a/nixos/modules/services/system/kerberos/heimdal.nix +++ b/nixos/modules/services/system/kerberos/heimdal.nix @@ -21,7 +21,10 @@ let target, ... }: - "${principal}\t${lib.concatStringsSep "," (lib.toList access)}\t${target}" + if target != "*" && target != "" then + "${principal}\t${lib.concatStringsSep "," (lib.toList access)}\t${target}" + else + "${principal}\t${lib.concatStringsSep "," (lib.toList access)}" ) acl )) (lib.mapAttrsToList ( @@ -70,6 +73,10 @@ in description = "Kerberos Administration Daemon"; partOf = [ "kerberos-server.target" ]; wantedBy = [ "kerberos-server.target" ]; + documentation = [ + "man:kadmind(8)" + "info:heimdal" + ]; serviceConfig = { ExecStart = "${package}/libexec/kadmind --config-file=/etc/heimdal-kdc/kdc.conf"; Slice = "system-kerberos-server.slice"; @@ -82,6 +89,10 @@ in description = "Key Distribution Center daemon"; partOf = [ "kerberos-server.target" ]; wantedBy = [ "kerberos-server.target" ]; + documentation = [ + "man:kdc(8)" + "info:heimdal" + ]; serviceConfig = { ExecStart = "${package}/libexec/kdc --config-file=/etc/heimdal-kdc/kdc.conf"; Slice = "system-kerberos-server.slice"; @@ -94,6 +105,10 @@ in description = "Kerberos Password Changing daemon"; partOf = [ "kerberos-server.target" ]; wantedBy = [ "kerberos-server.target" ]; + documentation = [ + "man:kpasswdd(8)" + "info:heimdal" + ]; serviceConfig = { ExecStart = "${package}/libexec/kpasswdd"; Slice = "system-kerberos-server.slice"; diff --git a/nixos/tests/kerberos/heimdal.nix b/nixos/tests/kerberos/heimdal.nix index e97e8797e05b..f12141d94627 100644 --- a/nixos/tests/kerberos/heimdal.nix +++ b/nixos/tests/kerberos/heimdal.nix @@ -3,63 +3,257 @@ import ../make-test-python.nix ( { name = "kerberos_server-heimdal"; - nodes.machine = - { - config, - libs, - pkgs, - ... - }: - { - services.kerberos_server = { - enable = true; - settings.realms = { - "FOO.BAR".acl = [ - { - principal = "admin"; - access = [ - "add" - "cpw" - ]; - } - ]; + nodes = { + server = + { config, pkgs, ... }: + { + imports = [ ../common/user-account.nix ]; + + users.users.alice.extraGroups = [ "wheel" ]; + + services.getty.autologinUser = "alice"; + + virtualisation.vlans = [ 1 ]; + + time.timeZone = "Etc/UTC"; + + networking = { + domain = "foo.bar"; + useDHCP = false; + firewall.enable = false; + hosts."10.0.0.1" = [ "server.foo.bar" ]; + hosts."10.0.0.2" = [ "client.foo.bar" ]; }; - }; - security.krb5 = { - enable = true; - package = pkgs.heimdal; - settings = { - libdefaults = { - default_realm = "FOO.BAR"; + + systemd.network.networks."01-eth1" = { + name = "eth1"; + networkConfig.Address = "10.0.0.1/24"; + }; + + security.krb5 = { + enable = true; + package = pkgs.heimdal; + settings = { + libdefaults.default_realm = "FOO.BAR"; + + # Enable extra debug output + logging = { + admin_server = "SYSLOG:DEBUG:AUTH"; + default = "SYSLOG:DEBUG:AUTH"; + kdc = "SYSLOG:DEBUG:AUTH"; + }; + + realms = { + "FOO.BAR" = { + admin_server = "server.foo.bar"; + kpasswd_server = "server.foo.bar"; + kdc = [ "server.foo.bar" ]; + }; + }; }; - realms = { + }; + + services.kerberos_server = { + enable = true; + settings.realms = { "FOO.BAR" = { - admin_server = "machine"; - kdc = "machine"; + acl = [ + { + principal = "kadmin/admin@FOO.BAR"; + access = "all"; + } + { + principal = "alice/admin@FOO.BAR"; + access = [ + "add" + "cpw" + "delete" + "get" + "list" + "modify" + ]; + } + ]; }; }; }; }; - }; - testScript = '' - machine.succeed( - "kadmin -l init --realm-max-ticket-life='8 day' --realm-max-renewable-life='10 day' FOO.BAR", - "systemctl restart kadmind.service kdc.service", - ) + client = + { config, pkgs, ... }: + { + imports = [ ../common/user-account.nix ]; - for unit in ["kadmind", "kdc", "kpasswdd"]: - machine.wait_for_unit(f"{unit}.service") + users.users.alice.extraGroups = [ "wheel" ]; - machine.succeed( - "kadmin -l add --password=admin_pw --use-defaults admin", - "kadmin -l ext_keytab --keytab=admin.keytab admin", - "kadmin -p admin -K admin.keytab add --password=alice_pw --use-defaults alice", - "kadmin -l ext_keytab --keytab=alice.keytab alice", - "kinit -kt alice.keytab alice", - ) - ''; + services.getty.autologinUser = "alice"; - meta.maintainers = [ pkgs.lib.maintainers.dblsaiko ]; + virtualisation.vlans = [ 1 ]; + + time.timeZone = "Etc/UTC"; + + networking = { + domain = "foo.bar"; + useDHCP = false; + hosts."10.0.0.1" = [ "server.foo.bar" ]; + hosts."10.0.0.2" = [ "client.foo.bar" ]; + }; + + systemd.network.networks."01-eth1" = { + name = "eth1"; + networkConfig.Address = "10.0.0.2/24"; + }; + + security.krb5 = { + enable = true; + package = pkgs.heimdal; + settings = { + libdefaults.default_realm = "FOO.BAR"; + + logging = { + admin_server = "SYSLOG:DEBUG:AUTH"; + default = "SYSLOG:DEBUG:AUTH"; + kdc = "SYSLOG:DEBUG:AUTH"; + }; + + realms = { + "FOO.BAR" = { + admin_server = "server.foo.bar"; + kpasswd_server = "server.foo.bar"; + kdc = [ "server.foo.bar" ]; + }; + }; + }; + }; + }; + }; + + testScript = + { nodes, ... }: + '' + import string + import random + random.seed(0) + + start_all() + + with subtest("Server: initialize realm"): + # for unit in ["kadmind.service", "kdc.socket", "kpasswdd.socket"]: + for unit in ["kadmind.service", "kdc.service", "kpasswdd.service"]: + server.wait_for_unit(unit) + + server.succeed("kadmin -l init --realm-max-ticket-life='8 day' --realm-max-renewable-life='10 day' FOO.BAR") + + for unit in ["kadmind.service", "kdc.service", "kpasswdd.service"]: + server.systemctl(f"restart {unit}") + + alice_krb_pw = "alice_hunter2" + alice_old_krb_pw = "" + alice_krb_admin_pw = "alice_admin_hunter2" + + def random_password(): + password_chars = string.ascii_letters + string.digits + string.punctuation.replace('"', "") + return "".join(random.choice(password_chars) for _ in range(16)) + + with subtest("Server: initialize user principals and keytabs"): + server.succeed(f'kadmin -l add --password="{alice_krb_admin_pw}" --use-defaults alice/admin') + server.succeed("kadmin -l ext_keytab --keytab=admin.keytab alice/admin") + + server.succeed(f'kadmin -p alice/admin -K admin.keytab add --password="{alice_krb_pw}" --use-defaults alice') + server.succeed("kadmin -l ext_keytab --keytab=alice.keytab alice") + + server.wait_for_unit("getty@tty1.service") + server.wait_until_succeeds("pgrep -f 'agetty.*tty1'") + server.wait_for_unit("default.target") + + with subtest("Server: initialize host principal with keytab"): + server.send_chars("sudo ktutil get -p alice/admin host/server.foo.bar\n") + server.wait_until_tty_matches("1", "password for alice:") + server.send_chars("${nodes.server.config.users.users.alice.password}\n") + server.wait_until_tty_matches("1", "alice/admin@FOO.BAR's Password:") + server.send_chars(f'{alice_krb_admin_pw}\n') + server.wait_for_file("/etc/krb5.keytab") + + ktutil_list = server.succeed("sudo ktutil list") + if not "host/server.foo.bar" in ktutil_list: + exit(1) + + server.send_chars("clear\n") + + client.systemctl("start network-online.target") + client.wait_for_unit("network-online.target") + client.wait_for_unit("getty@tty1.service") + client.wait_until_succeeds("pgrep -f 'agetty.*tty1'") + client.wait_for_unit("default.target") + + with subtest("Client: initialize host principal with keytab"): + client.succeed( + f'echo "{alice_krb_admin_pw}" > pw.txt', + "kinit -p --password-file=pw.txt alice/admin", + ) + + client.send_chars("sudo ktutil get -p alice/admin host/client.foo.bar\n") + client.wait_until_tty_matches("1", "password for alice:") + client.send_chars("${nodes.client.config.users.users.alice.password}\n") + client.wait_until_tty_matches("1", "alice/admin@FOO.BAR's Password:") + client.send_chars(f"{alice_krb_admin_pw}\n") + client.wait_for_file("/etc/krb5.keytab") + + ktutil_list = client.succeed("sudo ktutil list") + if not "host/client.foo.bar" in ktutil_list: + exit(1) + + client.send_chars("clear\n") + + with subtest("Client: kinit alice"): + client.succeed( + f"echo '{alice_krb_pw}' > pw.txt", + "kinit -p --password-file=pw.txt alice", + ) + tickets = client.succeed("klist") + assert "Principal: alice@FOO.BAR" in tickets + client.send_chars("clear\n") + + with subtest("Client: kpasswd alice"): + alice_old_krb_pw = alice_krb_pw + alice_krb_pw = random_password() + client.send_chars("kpasswd\n") + client.wait_until_tty_matches("1", "alice@FOO.BAR's Password:") + client.send_chars(f"{alice_old_krb_pw}\n", 0.1) + client.wait_until_tty_matches("1", "New password:") + client.send_chars(f"{alice_krb_pw}\n", 0.1) + client.wait_until_tty_matches("1", "Verify password - New password:") + client.send_chars(f"{alice_krb_pw}\n", 0.1) + + client.wait_until_tty_matches("1", "Success : Password changed") + + client.send_chars("clear\n") + + with subtest("Server: kinit alice"): + server.succeed( + "echo 'alice_pw_2' > pw.txt" + "kinit -p --password-file=pw.txt alice", + ) + tickets = client.succeed("klist") + assert "Principal: alice@FOO.BAR" in tickets + server.send_chars("clear\n") + + with subtest("Server: kpasswd alice"): + alice_old_krb_pw = alice_krb_pw + alice_krb_pw = random_password() + server.send_chars("kpasswd\n") + server.wait_until_tty_matches("1", "alice@FOO.BAR's Password:") + server.send_chars(f"{alice_old_krb_pw}\n", 0.1) + server.wait_until_tty_matches("1", "New password:") + server.send_chars(f"{alice_krb_pw}\n", 0.1) + server.wait_until_tty_matches("1", "Verify password - New password:") + server.send_chars(f"{alice_krb_pw}\n", 0.1) + + server.wait_until_tty_matches("1", "Success : Password changed") + + server.send_chars("clear\n") + ''; + + meta.maintainers = pkgs.heimdal.meta.maintainers; } ) diff --git a/pkgs/development/libraries/kerberos/heimdal.nix b/pkgs/development/libraries/kerberos/heimdal.nix index f8742d5183ae..56f8d9970997 100644 --- a/pkgs/development/libraries/kerberos/heimdal.nix +++ b/pkgs/development/libraries/kerberos/heimdal.nix @@ -202,6 +202,9 @@ stdenv.mkDerivation { description = "Implementation of Kerberos 5 (and some more stuff)"; license = licenses.bsd3; platforms = platforms.unix; - maintainers = with maintainers; [ h7x4 ]; + maintainers = with maintainers; [ + h7x4 + dblsaiko + ]; }; }