From 6cca9c0f9f2d7ed80ae52609160d2678e6fe38cd Mon Sep 17 00:00:00 2001 From: Kai Wohlfahrt Date: Mon, 6 Nov 2017 17:41:34 +0000 Subject: [PATCH] kerberos-server: add kerberos option Allow switching out kerberos server implementation. Sharing config is probably sensible, but implementation is different enough to be worth splitting into two files. Not sure this is the correct way to split an implementation, but it works for now. Uses the switch from config.krb5 to select implementation. --- nixos/modules/module-list.nix | 2 +- nixos/modules/services/system/kerberos.nix | 48 ------------ .../services/system/kerberos/default.nix | 76 +++++++++++++++++++ .../services/system/kerberos/heimdal.nix | 74 ++++++++++++++++++ .../modules/services/system/kerberos/mit.nix | 74 ++++++++++++++++++ nixos/tests/kerberos/default.nix | 5 ++ nixos/tests/kerberos/heimdal.nix | 53 +++++++++++++ nixos/tests/kerberos/mit.nix | 45 +++++++++++ 8 files changed, 328 insertions(+), 49 deletions(-) delete mode 100644 nixos/modules/services/system/kerberos.nix create mode 100644 nixos/modules/services/system/kerberos/default.nix create mode 100644 nixos/modules/services/system/kerberos/heimdal.nix create mode 100644 nixos/modules/services/system/kerberos/mit.nix create mode 100644 nixos/tests/kerberos/default.nix create mode 100644 nixos/tests/kerberos/heimdal.nix create mode 100644 nixos/tests/kerberos/mit.nix diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index e3e097dca26..a02352a2b93 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 694dee8c231..00000000000 --- a/nixos/modules/services/system/kerberos.nix +++ /dev/null @@ -1,48 +0,0 @@ -{pkgs, config, lib, ...}: - -let - inherit (lib) mkOption mkIf; - cfg = config.services.kerberos_server; - stateDir = "/var/heimdal"; -in - -{ - ###### interface - options = { - services.kerberos_server = { - enable = mkOption { - default = false; - description = '' - Enable the kerberos authentification server. - ''; - }; - - }; - }; - - - ###### implementation - - config = mkIf cfg.enable { - environment.systemPackages = [ pkgs.heimdalFull ]; - systemd.services.kadmind = { - description = "Kerberos Administration Daemon"; - serviceConfig.ExecStart = "${pkgs.heimdalFull}/libexec/heimdal/kadmind"; - }; - - systemd.services.kdc = { - description = "Key Distribution Center daemon"; - wantedBy = [ "multi-user.target" ]; - preStart = '' - mkdir -m 0755 -p ${stateDir} - ''; - serviceConfig.ExecStart = "${pkgs.heimdalFull}/libexec/heimdal/kdc"; - }; - - systemd.services.kpasswdd = { - description = "Kerberos Password Changing daemon"; - wantedBy = [ "multi-user.target" ]; - serviceConfig.ExecStart = "${pkgs.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 00000000000..90be7e8d551 --- /dev/null +++ b/nixos/modules/services/system/kerberos/default.nix @@ -0,0 +1,76 @@ +{pkgs, config, lib, ...}: + +let + inherit (lib) mkOption mkIf types; + 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 ]; + }; +} diff --git a/nixos/modules/services/system/kerberos/heimdal.nix b/nixos/modules/services/system/kerberos/heimdal.nix new file mode 100644 index 00000000000..554b1580810 --- /dev/null +++ b/nixos/modules/services/system/kerberos/heimdal.nix @@ -0,0 +1,74 @@ +{ pkgs, config, lib, ... } : + +let + inherit (lib) mkIf concatStringsSep concatMapStrings toList mapAttrs' + nameValuePair attrNames attrValues; + cfg = config.services.kerberos_server; + kerberos = config.krb5.kerberos; + stateDir = "/var/heimdal"; + aclFiles = mapAttrs' + (name: {acl, ...}: nameValuePair "${name}.acl" ( + pkgs.writeText "${name}.acl" (concatMapStrings (( + {principal, access, target, ...} : + "${principal}\t${concatStringsSep "," (toList access)}\t${target}\n" + )) acl) + )) cfg.realms; + + kdcConfigs = map (name: '' + database = { + dbname = ${stateDir}/heimdal + acl_file = /etc/heimdal-kdc/${name}.acl + } + '') (attrNames cfg.realms); + 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 ] ++ (attrValues aclFiles); + }; + + 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 ] ++ (attrValues aclFiles); + }; + + environment.etc = { + # Can be set via the --config-file option to KDC + "heimdal-kdc/kdc.conf".source = kdcConfFile; + } // ( + mapAttrs' + (name: value: nameValuePair "heimdal-kdc/${name}" {source = value;}) + aclFiles + ); + }; +} diff --git a/nixos/modules/services/system/kerberos/mit.nix b/nixos/modules/services/system/kerberos/mit.nix new file mode 100644 index 00000000000..9ff67f64728 --- /dev/null +++ b/nixos/modules/services/system/kerberos/mit.nix @@ -0,0 +1,74 @@ +{ pkgs, config, lib, ... } : + +let + inherit (lib) mkIf concatStrings concatStringsSep concatMapStrings toList + mapAttrs' nameValuePair attrNames 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, ...}: nameValuePair "${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 = map (name: '' + ${name} = { + acl_file = /etc/krb5kdc/${name}.acl + } + '') (attrNames cfg.realms); + 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 ] ++ (attrValues aclFiles); + 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; + } // ( + mapAttrs' + (name: value: nameValuePair "krb5kdc/${name}" {source = value;}) + aclFiles + ); + environment.variables = env; + }; +} diff --git a/nixos/tests/kerberos/default.nix b/nixos/tests/kerberos/default.nix new file mode 100644 index 00000000000..ae8bdb8bbc8 --- /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 00000000000..a0551b131e9 --- /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 00000000000..6da3a384aa9 --- /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"); + ''; +})