about summary refs log tree commit diff
path: root/nixos/modules/services/system/kerberos
diff options
context:
space:
mode:
Diffstat (limited to 'nixos/modules/services/system/kerberos')
-rw-r--r--nixos/modules/services/system/kerberos/default.nix84
-rw-r--r--nixos/modules/services/system/kerberos/heimdal.nix105
-rw-r--r--nixos/modules/services/system/kerberos/kerberos-server.md55
-rw-r--r--nixos/modules/services/system/kerberos/mit.nix78
4 files changed, 194 insertions, 128 deletions
diff --git a/nixos/modules/services/system/kerberos/default.nix b/nixos/modules/services/system/kerberos/default.nix
index 7fe970c9609a9..34c7c6c84f865 100644
--- a/nixos/modules/services/system/kerberos/default.nix
+++ b/nixos/modules/services/system/kerberos/default.nix
@@ -1,75 +1,59 @@
-{config, lib, ...}:
+{ config, pkgs, lib, ... }:
 
 let
-  inherit (lib) mkOption mkIf types length attrNames;
+  inherit (lib) mkOption types;
   cfg = config.services.kerberos_server;
-  kerberos = config.security.krb5.package;
+  inherit (config.security.krb5) package;
 
-  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.
-        '';
-      };
-    };
-  };
+  format = import ../../../security/krb5/krb5-conf-format.nix { inherit pkgs lib; } { enableKdcACLEntries = true; };
 in
 
 {
   imports = [
+    (lib.mkRenamedOptionModule [ "services" "kerberos_server" "realms" ] [ "services" "kerberos_server" "settings" "realms" ])
+
     ./mit.nix
     ./heimdal.nix
   ];
 
-  ###### interface
   options = {
     services.kerberos_server = {
       enable = lib.mkEnableOption "the kerberos authentication server";
 
-      realms = mkOption {
-        type = types.attrsOf (types.submodule realm);
+      settings = mkOption {
+        type = format.type;
         description = ''
-          The realm(s) to serve keys for.
+          Settings for the kerberos server of choice.
+
+          See the following documentation:
+          - Heimdal: {manpage}`kdc.conf(5)`
+          - MIT Kerberos: <https://web.mit.edu/kerberos/krb5-1.21/doc/admin/conf_files/kdc_conf.html>
         '';
+        default = { };
       };
     };
   };
 
+  config = lib.mkIf cfg.enable {
+    environment.systemPackages = [ package ];
+    assertions = [
+      {
+        assertion = cfg.settings.realms != { };
+        message = "The server needs at least one realm";
+      }
+      {
+        assertion = lib.length (lib.attrNames cfg.settings.realms) <= 1;
+        message = "Only one realm per server is currently supported.";
+      }
+    ];
+
+    systemd.slices.system-kerberos-server = { };
+    systemd.targets.kerberos-server = {
+      wantedBy = [ "multi-user.target" ];
+    };
+  };
 
-  ###### implementation
-
-  config = mkIf cfg.enable {
-    environment.systemPackages = [ kerberos ];
-    assertions = [{
-      assertion = length (attrNames cfg.realms) <= 1;
-      message = "Only one realm per server is currently supported.";
-    }];
+  meta = {
+    doc = ./kerberos-server.md;
   };
 }
diff --git a/nixos/modules/services/system/kerberos/heimdal.nix b/nixos/modules/services/system/kerberos/heimdal.nix
index ecafc92766704..cec4dd276e6b9 100644
--- a/nixos/modules/services/system/kerberos/heimdal.nix
+++ b/nixos/modules/services/system/kerberos/heimdal.nix
@@ -1,68 +1,87 @@
 { pkgs, config, lib, ... } :
 
 let
-  inherit (lib) mkIf concatStringsSep concatMapStrings toList mapAttrs
-    mapAttrsToList;
+  inherit (lib)  mapAttrs;
   cfg = config.services.kerberos_server;
-  kerberos = config.security.krb5.package;
-  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;
+  package = config.security.krb5.package;
 
-  kdcConfigs = mapAttrsToList (name: value: ''
-    database = {
-      dbname = ${stateDir}/heimdal
-      acl_file = ${value}
-    }
-  '') aclFiles;
-  kdcConfFile = pkgs.writeText "kdc.conf" ''
-    [kdc]
-    ${concatStringsSep "\n" kdcConfigs}
-  '';
+  aclConfigs = lib.pipe cfg.settings.realms [
+    (mapAttrs (name: { acl, ... }: lib.concatMapStringsSep "\n" (
+      { principal, access, target, ... }:
+      "${principal}\t${lib.concatStringsSep "," (lib.toList access)}\t${target}"
+    ) acl))
+    (lib.mapAttrsToList (name: text:
+      {
+        dbname = "/var/lib/heimdal/heimdal";
+        acl_file = pkgs.writeText "${name}.acl" text;
+      }
+    ))
+  ];
+
+  finalConfig = cfg.settings // {
+    realms = mapAttrs (_: v: removeAttrs v [ "acl" ]) (cfg.settings.realms or { });
+    kdc = (cfg.settings.kdc or { }) // {
+      database = aclConfigs;
+    };
+  };
+
+  format = import ../../../security/krb5/krb5-conf-format.nix { inherit pkgs lib; } { enableKdcACLEntries = true; };
+
+  kdcConfFile = format.generate "kdc.conf" finalConfig;
 in
 
 {
-  # No documentation about correct triggers, so guessing at them.
+  config = lib.mkIf (cfg.enable && package.passthru.implementation == "heimdal") {
+    environment.etc."heimdal-kdc/kdc.conf".source = kdcConfFile;
+
+    systemd.tmpfiles.settings."10-heimdal" = let
+      databases = lib.pipe finalConfig.kdc.database [
+        (map (dbAttrs: dbAttrs.dbname or null))
+        (lib.filter (x: x != null))
+        lib.unique
+      ];
+    in lib.genAttrs databases (_: {
+      d = {
+        user = "root";
+        group = "root";
+        mode = "0700";
+      };
+    });
 
-  config = mkIf (cfg.enable && kerberos == pkgs.heimdal) {
     systemd.services.kadmind = {
       description = "Kerberos Administration Daemon";
-      wantedBy = [ "multi-user.target" ];
-      preStart = ''
-        mkdir -m 0755 -p ${stateDir}
-      '';
-      serviceConfig.ExecStart =
-        "${kerberos}/libexec/kadmind --config-file=/etc/heimdal-kdc/kdc.conf";
+      partOf = [ "kerberos-server.target" ];
+      wantedBy = [ "kerberos-server.target" ];
+      serviceConfig = {
+        ExecStart = "${package}/libexec/kadmind --config-file=/etc/heimdal-kdc/kdc.conf";
+        Slice = "system-kerberos-server.slice";
+        StateDirectory = "heimdal";
+      };
       restartTriggers = [ kdcConfFile ];
     };
 
     systemd.services.kdc = {
       description = "Key Distribution Center daemon";
-      wantedBy = [ "multi-user.target" ];
-      preStart = ''
-        mkdir -m 0755 -p ${stateDir}
-      '';
-      serviceConfig.ExecStart =
-        "${kerberos}/libexec/kdc --config-file=/etc/heimdal-kdc/kdc.conf";
+      partOf = [ "kerberos-server.target" ];
+      wantedBy = [ "kerberos-server.target" ];
+      serviceConfig = {
+        ExecStart = "${package}/libexec/kdc --config-file=/etc/heimdal-kdc/kdc.conf";
+        Slice = "system-kerberos-server.slice";
+        StateDirectory = "heimdal";
+      };
       restartTriggers = [ kdcConfFile ];
     };
 
     systemd.services.kpasswdd = {
       description = "Kerberos Password Changing daemon";
-      wantedBy = [ "multi-user.target" ];
-      preStart = ''
-        mkdir -m 0755 -p ${stateDir}
-      '';
-      serviceConfig.ExecStart = "${kerberos}/libexec/kpasswdd";
+      partOf = [ "kerberos-server.target" ];
+      wantedBy = [ "kerberos-server.target" ];
+      serviceConfig = {
+        ExecStart = "${package}/libexec/kpasswdd";
+        Slice = "system-kerberos-server.slice";
+        StateDirectory = "heimdal";
+      };
       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/kerberos-server.md b/nixos/modules/services/system/kerberos/kerberos-server.md
new file mode 100644
index 0000000000000..80c71be1541e4
--- /dev/null
+++ b/nixos/modules/services/system/kerberos/kerberos-server.md
@@ -0,0 +1,55 @@
+# kerberos_server {#module-services-kerberos-server}
+
+Kerberos is a computer-network authentication protocol that works on the basis of tickets to allow nodes communicating over a non-secure network to prove their identity to one another in a secure manner.
+
+This module provides both the MIT and Heimdal implementations of the a Kerberos server.
+
+## Usage {#module-services-kerberos-server-usage}
+
+To enable a Kerberos server:
+
+```nix
+{
+  security.krb5 = {
+    # Here you can choose between the MIT and Heimdal implementations.
+    package = pkgs.krb5;
+    # package = pkgs.heimdal;
+
+    # Optionally set up a client on the same machine as the server
+    enable = true;
+    settings = {
+      libdefaults.default_realm = "EXAMPLE.COM";
+      realms."EXAMPLE.COM" = {
+        kdc = "kerberos.example.com";
+        admin_server = "kerberos.example.com";
+      };
+    };
+  }
+
+  services.kerberos-server = {
+    enable = true;
+    settings = {
+      realms."EXAMPLE.COM" = {
+        acl = [{ principal = "adminuser"; access=  ["add" "cpw"]; }];
+      };
+    };
+  };
+}
+```
+
+## Notes {#module-services-kerberos-server-notes}
+
+- The Heimdal documentation will sometimes assume that state is stored in `/var/heimdal`, but this module uses `/var/lib/heimdal` instead.
+- Due to the heimdal implementation being chosen through `security.krb5.package`, it is not possible to have a system with one implementation of the client and another of the server.
+- While `services.kerberos_server.settings` has a common freeform type between the two implementations, the actual settings that can be set can vary between the two implementations. To figure out what settings are available, you should consult the upstream documentation for the implementation you are using.
+
+## Upstream Documentation {#module-services-kerberos-server-upstream-documentation}
+
+- MIT Kerberos homepage: https://web.mit.edu/kerberos
+- MIT Kerberos docs: https://web.mit.edu/kerberos/krb5-latest/doc/index.html
+
+- Heimdal Kerberos GitHub wiki: https://github.com/heimdal/heimdal/wiki
+- Heimdal kerberos doc manpages (Debian unstable): https://manpages.debian.org/unstable/heimdal-docs/index.html
+- Heimdal Kerberos kdc manpages (Debian unstable): https://manpages.debian.org/unstable/heimdal-kdc/index.html
+
+Note the version number in the URLs, it may be different for the latest version.
diff --git a/nixos/modules/services/system/kerberos/mit.nix b/nixos/modules/services/system/kerberos/mit.nix
index a654bd1fe7e1b..9ce58986e27af 100644
--- a/nixos/modules/services/system/kerberos/mit.nix
+++ b/nixos/modules/services/system/kerberos/mit.nix
@@ -1,31 +1,37 @@
 { pkgs, config, lib, ... } :
 
 let
-  inherit (lib) mkIf concatStrings concatStringsSep concatMapStrings toList
-    mapAttrs mapAttrsToList;
+  inherit (lib) mapAttrs;
   cfg = config.services.kerberos_server;
-  kerberos = config.security.krb5.package;
-  stateDir = "/var/lib/krb5kdc";
+  package = config.security.krb5.package;
   PIDFile = "/run/kdc.pid";
+
+  format = import ../../../security/krb5/krb5-conf-format.nix { inherit pkgs lib; } { enableKdcACLEntries = true; };
+
   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}
-  '';
+
+  aclConfigs = lib.pipe cfg.settings.realms [
+    (mapAttrs (name: { acl, ... }: lib.concatMapStringsSep "\n" (
+      { principal, access, target, ... }: let
+        access_code = map (a: aclMap.${a}) (lib.toList access);
+      in "${principal} ${lib.concatStrings access_code} ${target}"
+    ) acl))
+
+    (lib.concatMapAttrs (name: text: {
+      ${name} = {
+        acl_file = pkgs.writeText "${name}.acl" text;
+      };
+    }))
+  ];
+
+  finalConfig = cfg.settings // {
+    realms = mapAttrs (n: v: (removeAttrs v [ "acl" ]) // aclConfigs.${n}) (cfg.settings.realms or { });
+  };
+
+  kdcConfFile = format.generate "kdc.conf" finalConfig;
   env = {
     # What Debian uses, could possibly link directly to Nix store?
     KRB5_KDC_PROFILE = "/etc/krb5kdc/kdc.conf";
@@ -33,36 +39,38 @@ let
 in
 
 {
-  config = mkIf (cfg.enable && kerberos == pkgs.krb5) {
+  config = lib.mkIf (cfg.enable && package.passthru.implementation == "krb5") {
+    environment = {
+      etc."krb5kdc/kdc.conf".source = kdcConfFile;
+      variables = env;
+    };
+
     systemd.services.kadmind = {
       description = "Kerberos Administration Daemon";
-      wantedBy = [ "multi-user.target" ];
-      preStart = ''
-        mkdir -m 0755 -p ${stateDir}
-      '';
-      serviceConfig.ExecStart = "${kerberos}/bin/kadmind -nofork";
+      partOf = [ "kerberos-server.target" ];
+      wantedBy = [ "kerberos-server.target" ];
+      serviceConfig = {
+        ExecStart = "${package}/bin/kadmind -nofork";
+        Slice = "system-kerberos-server.slice";
+        StateDirectory = "krb5kdc";
+      };
       restartTriggers = [ kdcConfFile ];
       environment = env;
     };
 
     systemd.services.kdc = {
       description = "Key Distribution Center daemon";
-      wantedBy = [ "multi-user.target" ];
-      preStart = ''
-        mkdir -m 0755 -p ${stateDir}
-      '';
+      partOf = [ "kerberos-server.target" ];
+      wantedBy = [ "kerberos-server.target" ];
       serviceConfig = {
         Type = "forking";
         PIDFile = PIDFile;
-        ExecStart = "${kerberos}/bin/krb5kdc -P ${PIDFile}";
+        ExecStart = "${package}/bin/krb5kdc -P ${PIDFile}";
+        Slice = "system-kerberos-server.slice";
+        StateDirectory = "krb5kdc";
       };
       restartTriggers = [ kdcConfFile ];
       environment = env;
     };
-
-    environment.etc = {
-      "krb5kdc/kdc.conf".source = kdcConfFile;
-    };
-    environment.variables = env;
   };
 }