diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index e3e097dca26f..a02352a2b93c 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -690,7 +690,7 @@ ./services/system/dbus.nix ./services/system/earlyoom.nix ./services/system/localtime.nix - ./services/system/kerberos.nix + ./services/system/kerberos/default.nix ./services/system/nscd.nix ./services/system/saslauthd.nix ./services/system/uptimed.nix diff --git a/nixos/modules/services/system/kerberos.nix b/nixos/modules/services/system/kerberos.nix deleted file mode 100644 index e2c45ed64ac0..000000000000 --- a/nixos/modules/services/system/kerberos.nix +++ /dev/null @@ -1,64 +0,0 @@ -{pkgs, config, lib, ...}: - -let - - inherit (lib) mkOption mkIf; - - inherit (pkgs) heimdalFull; - - stateDir = "/var/heimdal"; -in - -{ - - ###### interface - - options = { - - services.kerberos_server = { - - enable = mkOption { - default = false; - description = '' - Enable the kerberos authentification server. - ''; - }; - - }; - - }; - - - ###### implementation - - config = mkIf config.services.kerberos_server.enable { - - environment.systemPackages = [ heimdalFull ]; - - services.xinetd.enable = true; - services.xinetd.services = lib.singleton - { name = "kerberos-adm"; - flags = "REUSE NAMEINARGS"; - protocol = "tcp"; - user = "root"; - server = "${pkgs.tcp_wrappers}/bin/tcpd"; - serverArgs = "${pkgs.heimdalFull}/libexec/heimdal/kadmind"; - }; - - systemd.services.kdc = { - description = "Key Distribution Center daemon"; - wantedBy = [ "multi-user.target" ]; - preStart = '' - mkdir -m 0755 -p ${stateDir} - ''; - script = "${heimdalFull}/libexec/heimdal/kdc"; - }; - - systemd.services.kpasswdd = { - description = "Kerberos Password Changing daemon"; - wantedBy = [ "multi-user.target" ]; - script = "${heimdalFull}/libexec/heimdal/kpasswdd"; - }; - }; - -} diff --git a/nixos/modules/services/system/kerberos/default.nix b/nixos/modules/services/system/kerberos/default.nix new file mode 100644 index 000000000000..26ac85de402f --- /dev/null +++ b/nixos/modules/services/system/kerberos/default.nix @@ -0,0 +1,80 @@ +{pkgs, config, lib, ...}: + +let + inherit (lib) mkOption mkIf types length attrNames; + cfg = config.services.kerberos_server; + kerberos = config.krb5.kerberos; + + aclEntry = { + options = { + principal = mkOption { + type = types.str; + description = "Which principal the rule applies to"; + }; + access = mkOption { + type = types.either + (types.listOf (types.enum ["add" "cpw" "delete" "get" "list" "modify"])) + (types.enum ["all"]); + default = "all"; + description = "The changes the principal is allowed to make."; + }; + target = mkOption { + type = types.str; + default = "*"; + description = "The principals that 'access' applies to."; + }; + }; + }; + + realm = { + options = { + acl = mkOption { + type = types.listOf (types.submodule aclEntry); + default = [ + { principal = "*/admin"; access = "all"; } + { principal = "admin"; access = "all"; } + ]; + description = '' + The privileges granted to a user. + ''; + }; + }; + }; +in + +{ + imports = [ + ./mit.nix + ./heimdal.nix + ]; + + ###### interface + options = { + services.kerberos_server = { + enable = mkOption { + default = false; + description = '' + Enable the kerberos authentification server. + ''; + }; + + realms = mkOption { + type = types.attrsOf (types.submodule realm); + description = '' + The realm(s) to serve keys for. + ''; + }; + }; + }; + + + ###### implementation + + config = mkIf cfg.enable { + environment.systemPackages = [ kerberos ]; + assertions = [{ + assertion = length (attrNames cfg.realms) <= 1; + message = "Only one realm per server is currently supported."; + }]; + }; +} diff --git a/nixos/modules/services/system/kerberos/heimdal.nix b/nixos/modules/services/system/kerberos/heimdal.nix new file mode 100644 index 000000000000..d0f470f836ed --- /dev/null +++ b/nixos/modules/services/system/kerberos/heimdal.nix @@ -0,0 +1,68 @@ +{ pkgs, config, lib, ... } : + +let + inherit (lib) mkIf concatStringsSep concatMapStrings toList mapAttrs + mapAttrsToList attrValues; + cfg = config.services.kerberos_server; + kerberos = config.krb5.kerberos; + stateDir = "/var/heimdal"; + aclFiles = mapAttrs + (name: {acl, ...}: pkgs.writeText "${name}.acl" (concatMapStrings (( + {principal, access, target, ...} : + "${principal}\t${concatStringsSep "," (toList access)}\t${target}\n" + )) acl)) cfg.realms; + + kdcConfigs = mapAttrsToList (name: value: '' + database = { + dbname = ${stateDir}/heimdal + acl_file = ${value} + } + '') aclFiles; + kdcConfFile = pkgs.writeText "kdc.conf" '' + [kdc] + ${concatStringsSep "\n" kdcConfigs} + ''; +in + +{ + # No documentation about correct triggers, so guessing at them. + + config = mkIf (cfg.enable && kerberos == pkgs.heimdalFull) { + systemd.services.kadmind = { + description = "Kerberos Administration Daemon"; + wantedBy = [ "multi-user.target" ]; + preStart = '' + mkdir -m 0755 -p ${stateDir} + ''; + serviceConfig.ExecStart = + "${kerberos}/libexec/heimdal/kadmind --config-file=/etc/heimdal-kdc/kdc.conf"; + restartTriggers = [ kdcConfFile ]; + }; + + systemd.services.kdc = { + description = "Key Distribution Center daemon"; + wantedBy = [ "multi-user.target" ]; + preStart = '' + mkdir -m 0755 -p ${stateDir} + ''; + serviceConfig.ExecStart = + "${kerberos}/libexec/heimdal/kdc --config-file=/etc/heimdal-kdc/kdc.conf"; + restartTriggers = [ kdcConfFile ]; + }; + + systemd.services.kpasswdd = { + description = "Kerberos Password Changing daemon"; + wantedBy = [ "multi-user.target" ]; + preStart = '' + mkdir -m 0755 -p ${stateDir} + ''; + serviceConfig.ExecStart = "${kerberos}/libexec/heimdal/kpasswdd"; + restartTriggers = [ kdcConfFile ]; + }; + + environment.etc = { + # Can be set via the --config-file option to KDC + "heimdal-kdc/kdc.conf".source = kdcConfFile; + }; + }; +} diff --git a/nixos/modules/services/system/kerberos/mit.nix b/nixos/modules/services/system/kerberos/mit.nix new file mode 100644 index 000000000000..a53d9dd0c6b5 --- /dev/null +++ b/nixos/modules/services/system/kerberos/mit.nix @@ -0,0 +1,68 @@ +{ pkgs, config, lib, ... } : + +let + inherit (lib) mkIf concatStrings concatStringsSep concatMapStrings toList + mapAttrs mapAttrsToList attrValues; + cfg = config.services.kerberos_server; + kerberos = config.krb5.kerberos; + stateDir = "/var/lib/krb5kdc"; + PIDFile = "/run/kdc.pid"; + aclMap = { + add = "a"; cpw = "c"; delete = "d"; get = "i"; list = "l"; modify = "m"; + all = "*"; + }; + aclFiles = mapAttrs + (name: {acl, ...}: (pkgs.writeText "${name}.acl" (concatMapStrings ( + {principal, access, target, ...} : + let access_code = map (a: aclMap.${a}) (toList access); in + "${principal} ${concatStrings access_code} ${target}\n" + ) acl))) cfg.realms; + kdcConfigs = mapAttrsToList (name: value: '' + ${name} = { + acl_file = ${value} + } + '') aclFiles; + kdcConfFile = pkgs.writeText "kdc.conf" '' + [realms] + ${concatStringsSep "\n" kdcConfigs} + ''; + env = { + # What Debian uses, could possibly link directly to Nix store? + KRB5_KDC_PROFILE = "/etc/krb5kdc/kdc.conf"; + }; +in + +{ + config = mkIf (cfg.enable && kerberos == pkgs.krb5Full) { + systemd.services.kadmind = { + description = "Kerberos Administration Daemon"; + wantedBy = [ "multi-user.target" ]; + preStart = '' + mkdir -m 0755 -p ${stateDir} + ''; + serviceConfig.ExecStart = "${kerberos}/bin/kadmind -nofork"; + restartTriggers = [ kdcConfFile ]; + environment = env; + }; + + systemd.services.kdc = { + description = "Key Distribution Center daemon"; + wantedBy = [ "multi-user.target" ]; + preStart = '' + mkdir -m 0755 -p ${stateDir} + ''; + serviceConfig = { + Type = "forking"; + PIDFile = PIDFile; + ExecStart = "${kerberos}/bin/krb5kdc -P ${PIDFile}"; + }; + restartTriggers = [ kdcConfFile ]; + environment = env; + }; + + environment.etc = { + "krb5kdc/kdc.conf".source = kdcConfFile; + }; + environment.variables = env; + }; +} diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index feffdb97c18f..eddd6496bf47 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -107,6 +107,7 @@ in ipv6 = handleTest ./ipv6.nix {}; jenkins = handleTest ./jenkins.nix {}; kafka = handleTest ./kafka.nix {}; + kerberos = handleTest tests/kerberos/default.nix {}; kernel-latest = handleTest ./kernel-latest.nix {}; kernel-lts = handleTest ./kernel-lts.nix {}; keymap = handleTest ./keymap.nix {}; diff --git a/nixos/tests/kerberos/default.nix b/nixos/tests/kerberos/default.nix new file mode 100644 index 000000000000..ae8bdb8bbc82 --- /dev/null +++ b/nixos/tests/kerberos/default.nix @@ -0,0 +1,5 @@ +{ system ? builtins.currentSystem }: +{ + mit = import ./mit.nix { inherit system; }; + heimdal = import ./heimdal.nix { inherit system; }; +} diff --git a/nixos/tests/kerberos/heimdal.nix b/nixos/tests/kerberos/heimdal.nix new file mode 100644 index 000000000000..a0551b131e91 --- /dev/null +++ b/nixos/tests/kerberos/heimdal.nix @@ -0,0 +1,53 @@ +import ../make-test.nix ({pkgs, ...}: { + name = "kerberos_server-heimdal"; + machine = { config, libs, pkgs, ...}: + { services.kerberos_server = + { enable = true; + realms = { + "FOO.BAR".acl = [{principal = "admin"; access = ["add" "cpw"];}]; + }; + }; + krb5 = { + enable = true; + kerberos = pkgs.heimdalFull; + libdefaults = { + default_realm = "FOO.BAR"; + }; + realms = { + "FOO.BAR" = { + admin_server = "machine"; + kdc = "machine"; + }; + }; + }; + }; + + testScript = '' + $machine->start; + + $machine->succeed( + "kadmin -l init --realm-max-ticket-life='8 day' \\ + --realm-max-renewable-life='10 day' FOO.BAR" + ); + + $machine->succeed("systemctl restart kadmind.service kdc.service"); + $machine->waitForUnit("kadmind.service"); + $machine->waitForUnit("kdc.service"); + $machine->waitForUnit("kpasswdd.service"); + + $machine->succeed( + "kadmin -l add --password=admin_pw --use-defaults admin" + ); + $machine->succeed( + "kadmin -l ext_keytab --keytab=admin.keytab admin" + ); + $machine->succeed( + "kadmin -p admin -K admin.keytab add --password=alice_pw --use-defaults \\ + alice" + ); + $machine->succeed( + "kadmin -l ext_keytab --keytab=alice.keytab alice" + ); + $machine->succeed("kinit -kt alice.keytab alice"); + ''; +}) diff --git a/nixos/tests/kerberos/mit.nix b/nixos/tests/kerberos/mit.nix new file mode 100644 index 000000000000..6da3a384aa99 --- /dev/null +++ b/nixos/tests/kerberos/mit.nix @@ -0,0 +1,45 @@ +import ../make-test.nix ({pkgs, ...}: { + name = "kerberos_server-mit"; + machine = { config, libs, pkgs, ...}: + { services.kerberos_server = + { enable = true; + realms = { + "FOO.BAR".acl = [{principal = "admin"; access = ["add" "cpw"];}]; + }; + }; + krb5 = { + enable = true; + kerberos = pkgs.krb5Full; + libdefaults = { + default_realm = "FOO.BAR"; + }; + realms = { + "FOO.BAR" = { + admin_server = "machine"; + kdc = "machine"; + }; + }; + }; + users.extraUsers.alice = { isNormalUser = true; }; + }; + + testScript = '' + $machine->start; + + $machine->succeed( + "kdb5_util create -s -r FOO.BAR -P master_key" + ); + + $machine->succeed("systemctl restart kadmind.service kdc.service"); + $machine->waitForUnit("kadmind.service"); + $machine->waitForUnit("kdc.service"); + + $machine->succeed( + "kadmin.local add_principal -pw admin_pw admin" + ); + $machine->succeed( + "kadmin -p admin -w admin_pw addprinc -pw alice_pw alice" + ); + $machine->succeed("echo alice_pw | sudo -u alice kinit"); + ''; +}) diff --git a/pkgs/development/libraries/kerberos/krb5.nix b/pkgs/development/libraries/kerberos/krb5.nix index 165f9139ff1f..50a669b053f9 100644 --- a/pkgs/development/libraries/kerberos/krb5.nix +++ b/pkgs/development/libraries/kerberos/krb5.nix @@ -65,7 +65,7 @@ stdenv.mkDerivation rec { # not via outputBin, due to reference from libkrb5.so postInstall = '' - moveToOutput bin "$dev" + moveToOutput bin/krb5-config "$dev" ''; enableParallelBuilding = true;