From c16238a88fcde4db1414baf161fffb0c452c91c5 Mon Sep 17 00:00:00 2001 From: h7x4 Date: Wed, 17 Jan 2024 00:25:22 +0100 Subject: [PATCH] WIP: init buskerud/salsa --- flake.lock | 32 ++-- flake.nix | 10 + hosts/buskerud/configuration.nix | 2 + hosts/buskerud/containers/salsa/NOTES.md | 27 +++ .../containers/salsa/configuration.nix | 51 +++++ .../salsa/modules/kerberos/default.nix | 101 ++++++++++ .../salsa/modules/kerberos/heimdal.nix | 87 +++++++++ .../containers/salsa/modules/kerberos/mit.nix | 77 ++++++++ .../containers/salsa/modules/krb5/default.nix | 104 ++++++++++ .../salsa/modules/krb5/krb5-conf-format.nix | 96 ++++++++++ .../salsa/services/heimdal/default.nix | 78 ++++++++ .../salsa/services/heimdal/package.nix | 180 ++++++++++++++++++ .../salsa/services/heimdal/package2.nix | 178 +++++++++++++++++ .../containers/salsa/services/openldap.nix | 115 +++++++++++ .../containers/salsa/services/saslauthd.nix | 14 ++ 15 files changed, 1136 insertions(+), 16 deletions(-) create mode 100644 hosts/buskerud/containers/salsa/NOTES.md create mode 100644 hosts/buskerud/containers/salsa/configuration.nix create mode 100644 hosts/buskerud/containers/salsa/modules/kerberos/default.nix create mode 100644 hosts/buskerud/containers/salsa/modules/kerberos/heimdal.nix create mode 100644 hosts/buskerud/containers/salsa/modules/kerberos/mit.nix create mode 100644 hosts/buskerud/containers/salsa/modules/krb5/default.nix create mode 100644 hosts/buskerud/containers/salsa/modules/krb5/krb5-conf-format.nix create mode 100644 hosts/buskerud/containers/salsa/services/heimdal/default.nix create mode 100644 hosts/buskerud/containers/salsa/services/heimdal/package.nix create mode 100644 hosts/buskerud/containers/salsa/services/heimdal/package2.nix create mode 100644 hosts/buskerud/containers/salsa/services/openldap.nix create mode 100644 hosts/buskerud/containers/salsa/services/saslauthd.nix diff --git a/flake.lock b/flake.lock index cd45580..66b8828 100644 --- a/flake.lock +++ b/flake.lock @@ -7,11 +7,11 @@ ] }, "locked": { - "lastModified": 1702569759, - "narHash": "sha256-Ze3AdEEsVZBRJ4wn13EZpV1Uubkzi59TkC4j2G9xoFI=", + "lastModified": 1709632354, + "narHash": "sha256-jxRHwqrtNze51WKFKvxlQ8Inf62UNRl5cFqEQ2V96vE=", "owner": "nix-community", "repo": "disko", - "rev": "98ab91109716871f50ea8cb0e0ac7cc1e1e14714", + "rev": "0d11aa8d6431326e10b8656420f91085c3bd0b12", "type": "github" }, "original": { @@ -80,11 +80,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1702601832, - "narHash": "sha256-z+GyetKtwj7ZVZrRcI73N8Xy1B3JGAqDyPniBFRpIgo=", + "lastModified": 1709565521, + "narHash": "sha256-YP3H7Lm3IhOKHIcn+qMCLRINJG313Io5CjvNTJyrnhY=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "dff64d4ba6e9dc3f0a4ef8737f372a528d5bc8d1", + "rev": "9a5f1a573376eeb8c525f936eed32fabfb6e81be", "type": "github" }, "original": { @@ -110,27 +110,27 @@ }, "nixpkgs-stable": { "locked": { - "lastModified": 1702148972, - "narHash": "sha256-h2jODFP6n+ABrUWcGRSVPRFfLOkM9TJ2pO+h+9JcaL0=", + "lastModified": 1709428628, + "narHash": "sha256-//ZCCnpVai/ShtO2vPjh3AWgo8riXCaret6V9s7Hew4=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "b8f33c044e51de6dde3ad80a9676945e0e4e3227", + "rev": "66d65cb00b82ffa04ee03347595aa20e41fe3555", "type": "github" }, "original": { "owner": "NixOS", - "ref": "release-23.05", + "ref": "release-23.11", "repo": "nixpkgs", "type": "github" } }, "nixpkgs-unstable": { "locked": { - "lastModified": 1702635820, - "narHash": "sha256-rClms9NTmSL/WIN5VmEccVhUExMkjCrRNswxU9QGNNo=", + "lastModified": 1712963716, + "narHash": "sha256-WKm9CvgCldeIVvRz87iOMi8CFVB1apJlkUT4GGvA0iM=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "02357adddd0889782362d999628de9d309d202dc", + "rev": "cfd6b5fc90b15709b780a5a1619695a88505a176", "type": "github" }, "original": { @@ -179,11 +179,11 @@ "nixpkgs-stable": "nixpkgs-stable" }, "locked": { - "lastModified": 1702177193, - "narHash": "sha256-J2409SyXROoUHYXVy9h4Pj0VU8ReLuy/mzBc9iK4DBg=", + "lastModified": 1709591996, + "narHash": "sha256-0sQcalXSgqlO6mnxBTXkSQChBHy2GQsokB1XY8r+LpQ=", "owner": "Mic92", "repo": "sops-nix", - "rev": "d806e546f96c88cd9f7d91c1c19ebc99ba6277d9", + "rev": "291aad29b59ceda517a06e59809f35cb0bb17c6b", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 16d4612..bb518f1 100644 --- a/flake.nix +++ b/flake.nix @@ -123,12 +123,22 @@ packages = { "x86_64-linux" = let pkgs = nixpkgs.legacyPackages."x86_64-linux"; + pkgs-unstable = nixpkgs-unstable.legacyPackages."x86_64-linux"; in rec { default = important-machines; important-machines = pkgs.linkFarm "important-machines" (nixlib.getAttrs importantMachines self.packages.x86_64-linux); all-machines = pkgs.linkFarm "all-machines" (nixlib.getAttrs allMachines self.packages.x86_64-linux); + heimdal = pkgs.callPackage hosts/buskerud/containers/salsa/services/heimdal/package.nix { + inherit (pkgs.apple_sdk.frameworks) + CoreFoundation Security SystemConfiguration; + }; + heimdal-unstable = pkgs-unstable.callPackage hosts/buskerud/containers/salsa/services/heimdal/package.nix { + inherit (pkgs.apple_sdk.frameworks) + CoreFoundation Security SystemConfiguration; + }; + inherit pkgs pkgs-unstable; } // nixlib.genAttrs allMachines (machine: self.nixosConfigurations.${machine}.config.system.build.toplevel); }; diff --git a/hosts/buskerud/configuration.nix b/hosts/buskerud/configuration.nix index 14eec65..990e063 100644 --- a/hosts/buskerud/configuration.nix +++ b/hosts/buskerud/configuration.nix @@ -4,6 +4,8 @@ ./hardware-configuration.nix ../../base.nix ../../misc/metrics-exporters.nix + + ./containers/salsa/configuration.nix ]; # buskerud does not support efi? diff --git a/hosts/buskerud/containers/salsa/NOTES.md b/hosts/buskerud/containers/salsa/NOTES.md new file mode 100644 index 0000000..e5840ee --- /dev/null +++ b/hosts/buskerud/containers/salsa/NOTES.md @@ -0,0 +1,27 @@ +# Misc docs + +### Old stuff about storing kerberos state inside LDAP - might not be relevant + +- https://wiki.debian.org/LDAP/OpenLDAPSetup#OpenLDAP_as_a_Backend +- https://ubuntu.com/server/docs/service-kerberos-with-openldap-backend +- https://forums.freebsd.org/threads/heimdal-and-openldap-integration-some-questions.58422/ +- http://osr507doc.sco.com/cgi-bin/info2html?(heimdal.info.gz)Using%2520LDAP%2520to%2520store%2520the%2520database&lang=en +- https://bbs.archlinux.org/viewtopic.php?id=54236 +- https://openldap-software.0penldap.narkive.com/Ml6seAGL/ldap-backend-for-heimdal-kerberos + +### Heimdal setup + +- http://chschneider.eu/linux/server/heimdal.shtml +- https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/kerberos/heimdal.nix +- https://itk.samfundet.no/dok/Kerberos (possibly a bit dated) + +### OpenLDAP setup with new olc stuff + +- https://www.openldap.org/doc/admin26/ +- https://www.openldap.org/doc/admin26/sasl.html#GSSAPI +- https://www.zytrax.com/books/ldap/ + +### SASLAUTHD + +- https://linux.die.net/man/8/saslauthd +- https://www.cyrusimap.org/sasl/index.html diff --git a/hosts/buskerud/containers/salsa/configuration.nix b/hosts/buskerud/containers/salsa/configuration.nix new file mode 100644 index 0000000..0eec5d2 --- /dev/null +++ b/hosts/buskerud/containers/salsa/configuration.nix @@ -0,0 +1,51 @@ +{ config, pkgs, lib, inputs, values, ... }: +{ + containers.salsa = { + autoStart = true; + interfaces = [ "enp6s0f1" ]; + bindMounts = { + "/data" = { hostPath = "/data/salsa"; isReadOnly = false; }; + }; + nixpkgs = inputs.nixpkgs-unstable; + + config = { config, pkgs, ... }: let + inherit values inputs; + in { + imports = [ + inputs.sops-nix.nixosModules.sops + ../../../../base.nix + + ./services/heimdal + ./services/openldap.nix + ./services/saslauthd.nix + + # https://github.com/NixOS/nixpkgs/pull/287611 + ./modules/krb5 + ./modules/kerberos + ]; + + disabledModules = [ + "security/krb5" + "services/system/kerberos/default.nix" + ]; + + _module.args = { + inherit values inputs; + }; + + sops.age.sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ]; + sops.age.keyFile = "/var/lib/sops-nix/key.txt"; + sops.age.generateKey = true; + + # systemd.network.networks."30-enp6s0f1" = values.defaultNetworkConfig // { + # matchConfig.Name = "enp6s0f1"; + # address = with values.hosts.jokum; [ (ipv4 + "/25") (ipv6 + "/64") ] + # ++ (with values.services.turn; [ (ipv4 + "/25") (ipv6 + "/64") ]); + # }; + + networking.useHostResolvConf = lib.mkForce false; + + system.stateVersion = "23.11"; + }; + }; +} diff --git a/hosts/buskerud/containers/salsa/modules/kerberos/default.nix b/hosts/buskerud/containers/salsa/modules/kerberos/default.nix new file mode 100644 index 0000000..ac5ec4d --- /dev/null +++ b/hosts/buskerud/containers/salsa/modules/kerberos/default.nix @@ -0,0 +1,101 @@ +{ config, pkgs, lib, ... }: + +let + inherit (lib) mkOption types; + cfg = config.services.kerberos_server; + inherit (config.security.krb5) package; + + format = import ../krb5/krb5-conf-format.nix { inherit pkgs lib; } { }; +in + +{ + imports = [ + (lib.mkRenamedOptionModule [ "services" "kerberos_server" "realms" ] [ "services" "kerberos_server" "settings" "realms" ]) + + ./mit.nix + ./heimdal.nix + ]; + + options = { + services.kerberos_server = { + enable = lib.mkEnableOption (lib.mdDoc "the kerberos authentication server"); + + settings = let + aclEntry = types.submodule { + options = { + principal = mkOption { + type = types.str; + description = lib.mdDoc "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 = lib.mdDoc "The changes the principal is allowed to make."; + }; + target = mkOption { + type = types.str; + default = "*"; + description = lib.mdDoc "The principals that 'access' applies to."; + }; + }; + }; + + realm = types.submodule ({ name, ... }: { + freeformType = format.sectionType; + options = { + acl = mkOption { + type = types.listOf aclEntry; + default = [ + { principal = "*/admin"; access = "all"; } + { principal = "admin"; access = "all"; } + ]; + description = lib.mdDoc '' + The privileges granted to a user. + ''; + }; + }; + }); + in mkOption { + type = types.submodule (format.type.getSubModules ++ [{ + options = { + realms = mkOption { + type = types.attrsOf realm; + description = lib.mdDoc '' + The realm(s) to serve keys for. + ''; + }; + }; + }]); + description = '' + Settings for the kerberos server of choice. + + See the following documentation: + - Heimdal: {manpage}`kdc.conf(5)` + - MIT Kerberos: + ''; + 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" ]; + }; + }; +} diff --git a/hosts/buskerud/containers/salsa/modules/kerberos/heimdal.nix b/hosts/buskerud/containers/salsa/modules/kerberos/heimdal.nix new file mode 100644 index 0000000..7a7b692 --- /dev/null +++ b/hosts/buskerud/containers/salsa/modules/kerberos/heimdal.nix @@ -0,0 +1,87 @@ +{ pkgs, config, lib, ... } : + +let + inherit (lib) mapAttrs; + cfg = config.services.kerberos_server; + package = config.security.krb5.package; + + 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 ../krb5/krb5-conf-format.nix { inherit pkgs lib; } { }; + + kdcConfFile = format.generate "kdc.conf" finalConfig; +in + +{ + 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"; + }; + }); + + systemd.services.kadmind = { + description = "Kerberos Administration Daemon"; + 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"; + 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"; + partOf = [ "kerberos-server.target" ]; + wantedBy = [ "kerberos-server.target" ]; + serviceConfig = { + ExecStart = "${package}/libexec/kpasswdd"; + Slice = "system-kerberos-server.slice"; + StateDirectory = "heimdal"; + }; + restartTriggers = [ kdcConfFile ]; + }; + }; +} diff --git a/hosts/buskerud/containers/salsa/modules/kerberos/mit.nix b/hosts/buskerud/containers/salsa/modules/kerberos/mit.nix new file mode 100644 index 0000000..5953480 --- /dev/null +++ b/hosts/buskerud/containers/salsa/modules/kerberos/mit.nix @@ -0,0 +1,77 @@ +{ pkgs, config, lib, ... } : + +let + inherit (lib) mapAttrs; + cfg = config.services.kerberos_server; + package = config.security.krb5.package; + PIDFile = "/run/kdc.pid"; + + format = import ../krb5/krb5-conf-format.nix { inherit pkgs lib; } { }; + + aclMap = { + add = "a"; cpw = "c"; delete = "d"; get = "i"; list = "l"; modify = "m"; + all = "*"; + }; + + 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"; + }; +in + +{ + 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"; + 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"; + partOf = [ "kerberos-server.target" ]; + wantedBy = [ "kerberos-server.target" ]; + serviceConfig = { + Type = "forking"; + PIDFile = PIDFile; + ExecStart = "${package}/bin/krb5kdc -P ${PIDFile}"; + Slice = "system-kerberos-server.slice"; + StateDirectory = "krb5kdc"; + }; + restartTriggers = [ kdcConfFile ]; + environment = env; + }; + }; +} + diff --git a/hosts/buskerud/containers/salsa/modules/krb5/default.nix b/hosts/buskerud/containers/salsa/modules/krb5/default.nix new file mode 100644 index 0000000..a3dacb2 --- /dev/null +++ b/hosts/buskerud/containers/salsa/modules/krb5/default.nix @@ -0,0 +1,104 @@ +{ config, lib, pkgs, ... }: +let + inherit (lib) mdDoc mkIf mkOption mkPackageOption mkRemovedOptionModule; + inherit (lib.types) bool; + + mkRemovedOptionModule' = name: reason: mkRemovedOptionModule ["krb5" name] reason; + mkRemovedOptionModuleCfg = name: mkRemovedOptionModule' name '' + The option `krb5.${name}' has been removed. Use + `security.krb5.settings.${name}' for structured configuration. + ''; + + cfg = config.security.krb5; + format = import ./krb5-conf-format.nix { inherit pkgs lib; } { }; +in { + imports = [ + (mkRemovedOptionModuleCfg "libdefaults") + (mkRemovedOptionModuleCfg "realms") + (mkRemovedOptionModuleCfg "domain_realm") + (mkRemovedOptionModuleCfg "capaths") + (mkRemovedOptionModuleCfg "appdefaults") + (mkRemovedOptionModuleCfg "plugins") + (mkRemovedOptionModuleCfg "config") + (mkRemovedOptionModuleCfg "extraConfig") + (mkRemovedOptionModule' "kerberos" '' + The option `krb5.kerberos' has been moved to `security.krb5.package'. + '') + ]; + + options = { + security.krb5 = { + enable = mkOption { + default = false; + description = mdDoc "Enable and configure Kerberos utilities"; + type = bool; + }; + + package = mkPackageOption pkgs "krb5" { + example = "heimdal"; + }; + + settings = mkOption { + default = { }; + type = format.type; + description = mdDoc '' + Structured contents of the {file}`krb5.conf` file. See + {manpage}`krb5.conf(5)` for details about configuration. + ''; + example = { + include = [ "/run/secrets/secret-krb5.conf" ]; + includedir = [ "/run/secrets/secret-krb5.conf.d" ]; + + libdefaults = { + default_realm = "ATHENA.MIT.EDU"; + }; + + realms = { + "ATHENA.MIT.EDU" = { + admin_server = "athena.mit.edu"; + kdc = [ + "athena01.mit.edu" + "athena02.mit.edu" + ]; + }; + }; + + domain_realm = { + "mit.edu" = "ATHENA.MIT.EDU"; + }; + + logging = { + kdc = "SYSLOG:NOTICE"; + admin_server = "SYSLOG:NOTICE"; + default = "SYSLOG:NOTICE"; + }; + }; + }; + }; + }; + + config = { + assertions = mkIf (cfg.enable || config.services.kerberos_server.enable) [(let + implementation = cfg.package.passthru.implementation or ""; + in { + assertion = lib.elem implementation [ "krb5" "heimdal" ]; + message = '' + `security.krb5.package` must be one of: + + - krb5 + - heimdal + + Currently chosen implementation: ${implementation} + ''; + })]; + + environment = mkIf cfg.enable { + systemPackages = [ cfg.package ]; + etc."krb5.conf".source = format.generate "krb5.conf" cfg.settings; + }; + }; + + meta.maintainers = builtins.attrValues { + inherit (lib.maintainers) dblsaiko h7x4; + }; +} diff --git a/hosts/buskerud/containers/salsa/modules/krb5/krb5-conf-format.nix b/hosts/buskerud/containers/salsa/modules/krb5/krb5-conf-format.nix new file mode 100644 index 0000000..807c3b5 --- /dev/null +++ b/hosts/buskerud/containers/salsa/modules/krb5/krb5-conf-format.nix @@ -0,0 +1,96 @@ +{ pkgs, lib, ... }: + +# Based on +# - https://web.mit.edu/kerberos/krb5-1.12/doc/admin/conf_files/krb5_conf.html +# - https://manpages.debian.org/unstable/heimdal-docs/krb5.conf.5heimdal.en.html + +let + inherit (lib) boolToString concatMapStringsSep concatStringsSep filter + isAttrs isBool isList mapAttrsToList mdDoc mkOption singleton splitString; + inherit (lib.types) attrsOf bool coercedTo either int listOf oneOf path + str submodule; +in +{ }: rec { + sectionType = let + relation = oneOf [ + (listOf (attrsOf value)) + (attrsOf value) + value + ]; + value = either (listOf atom) atom; + atom = oneOf [int str bool]; + in attrsOf relation; + + type = submodule { + freeformType = attrsOf sectionType; + options = { + include = mkOption { + default = [ ]; + description = mdDoc '' + Files to include in the Kerberos configuration. + ''; + type = coercedTo path singleton (listOf path); + }; + includedir = mkOption { + default = [ ]; + description = mdDoc '' + Directories containing files to include in the Kerberos configuration. + ''; + type = coercedTo path singleton (listOf path); + }; + module = mkOption { + default = [ ]; + description = mdDoc '' + Modules to obtain Kerberos configuration from. + ''; + type = coercedTo path singleton (listOf path); + }; + }; + }; + + generate = let + indent = str: concatMapStringsSep "\n" (line: " " + line) (splitString "\n" str); + + formatToplevel = args @ { + include ? [ ], + includedir ? [ ], + module ? [ ], + ... + }: let + sections = removeAttrs args [ "include" "includedir" "module" ]; + in concatStringsSep "\n" (filter (x: x != "") [ + (concatStringsSep "\n" (mapAttrsToList formatSection sections)) + (concatMapStringsSep "\n" (m: "module ${m}") module) + (concatMapStringsSep "\n" (i: "include ${i}") include) + (concatMapStringsSep "\n" (i: "includedir ${i}") includedir) + ]); + + formatSection = name: section: '' + [${name}] + ${indent (concatStringsSep "\n" (mapAttrsToList formatRelation section))} + ''; + + formatRelation = name: relation: + if isAttrs relation + then '' + ${name} = { + ${indent (concatStringsSep "\n" (mapAttrsToList formatValue relation))} + }'' + else if isList relation + then + concatMapStringsSep "\n" (formatRelation name) relation + else formatValue name relation; + + formatValue = name: value: + if isList value + then concatMapStringsSep "\n" (formatAtom name) value + else formatAtom name value; + + formatAtom = name: atom: let + v = if isBool atom then boolToString atom else toString atom; + in "${name} = ${v}"; + in + name: value: pkgs.writeText name '' + ${formatToplevel value} + ''; +} diff --git a/hosts/buskerud/containers/salsa/services/heimdal/default.nix b/hosts/buskerud/containers/salsa/services/heimdal/default.nix new file mode 100644 index 0000000..033b063 --- /dev/null +++ b/hosts/buskerud/containers/salsa/services/heimdal/default.nix @@ -0,0 +1,78 @@ +{ config, pkgs, lib, ... }: +let + + realm = "PVV.NTNU.NO"; + + cfg = config.security.krb5; +in +{ + security.krb5 = { + enable = true; + + # NOTE: This has a small edit that moves an include header to $dev/include. + # It is required in order to build smbk5pwd, because of some nested includes. + # We should open an issue upstream (heimdal, not nixpkgs), but this patch + # will do for now. + # package = pkgs.heimdal; + package = pkgs.callPackage ./package.nix { + inherit (pkgs.apple_sdk.frameworks) + CoreFoundation Security SystemConfiguration; + }; + + settings = { + logging.kdc = "CONSOLE"; + realms.${realm} = { + admin_server = "localhost"; + kdc = [ "localhost" ]; + }; + + kadmin.default_keys = lib.concatStringsSep " " [ + "aes256-cts-hmac-sha1-96:pw-salt" + "aes128-cts-hmac-sha1-96:pw-salt" + ]; + + libdefaults.default_etypes = lib.concatStringsSep " " [ + "aes256-cts-hmac-sha1-96" + "aes128-cts-hmac-sha1-96" + ]; + + libdefaults = { + default_realm = realm; + }; + + domain_realm = { + "pvv.ntnu.no" = realm; + ".pvv.ntnu.no" = realm; + }; + }; + }; + + services.kerberos_server = { + enable = true; + settings = { + realms.${realm} = { + dbname = "/var/heimdal/heimdal"; + mkey = "/var/heimdal/mkey"; + }; + # kadmin.default_keys = lib.concatStringsSep " " [ + # "aes256-cts-hmac-sha1-96:pw-salt" + # "aes128-cts-hmac-sha1-96:pw-salt" + # ]; + + # libdefaults.default_etypes = lib.concatStringsSep " " [ + # "aes256-cts-hmac-sha1-96" + # "aes128-cts-hmac-sha1-96" + # ]; + + # password_quality.min_length = 8; + }; + }; + + # NOTE: These changes are part of nixpkgs-unstable, but not 23.11. + # The package override needs these changes. + # systemd.services = { + # kdc.serviceConfig.ExecStart = lib.mkForce "${cfg.package}/libexec/kadmind --config-file=/etc/heimdal-kdc/kdc.conf"; + # kpasswdd.serviceConfig.ExecStart = lib.mkForce "${cfg.package}/libexec/kpasswdd"; + # kadmind.serviceConfig.ExecStart = lib.mkForce "${cfg.package}/libexec/kdc --config-file=/etc/heimdal-kdc/kdc.conf"; + # }; +} diff --git a/hosts/buskerud/containers/salsa/services/heimdal/package.nix b/hosts/buskerud/containers/salsa/services/heimdal/package.nix new file mode 100644 index 0000000..e4beb70 --- /dev/null +++ b/hosts/buskerud/containers/salsa/services/heimdal/package.nix @@ -0,0 +1,180 @@ +{ lib +, stdenv +, fetchFromGitHub +, autoreconfHook +, pkg-config +, python3 +, perl +, bison +, flex +, texinfo +, perlPackages + +, openldap +, libcap_ng +, sqlite +, openssl +, db +, libedit +, pam +, krb5 +, libmicrohttpd +, cjson + +, CoreFoundation +, Security +, SystemConfiguration + +, curl +, jdk +, unzip +, which + +, nixosTests + +, withCJSON ? true +, withCapNG ? stdenv.isLinux +# libmicrohttpd should theoretically work for darwin as well, but something is broken. +# It affects tests check-bx509d and check-httpkadmind. +, withMicroHTTPD ? stdenv.isLinux +, withOpenLDAP ? true +, withOpenLDAPAsHDBModule ? false +, withOpenSSL ? true +, withSQLite3 ? true +}: + +assert lib.assertMsg (withOpenLDAPAsHDBModule -> withOpenLDAP) '' + OpenLDAP needs to be enabled in order to build the OpenLDAP HDB Module. +''; + +stdenv.mkDerivation { + pname = "heimdal"; + version = "7.8.0-unstable-2023-11-29"; + + src = fetchFromGitHub { + owner = "heimdal"; + repo = "heimdal"; + rev = "3253c49544eacb33d5ad2f6f919b0696e5aab794"; + hash = "sha256-uljzQBzXrZCZjcIWfioqHN8YsbUUNy14Vo+A3vZIXzM="; + }; + + outputs = [ "out" "dev" "man" "info" ]; + + nativeBuildInputs = [ + autoreconfHook + pkg-config + python3 + perl + bison + flex + texinfo + ] + ++ (with perlPackages; [ JSON ]); + + buildInputs = [ db libedit pam ] + ++ lib.optionals (stdenv.isDarwin) [ CoreFoundation Security SystemConfiguration ] + ++ lib.optionals (withCJSON) [ cjson ] + ++ lib.optionals (withCapNG) [ libcap_ng ] + ++ lib.optionals (withMicroHTTPD) [ libmicrohttpd ] + ++ lib.optionals (withOpenLDAP) [ openldap ] + ++ lib.optionals (withOpenSSL) [ openssl ] + ++ lib.optionals (withSQLite3) [ sqlite ]; + + doCheck = true; + nativeCheckInputs = [ + curl + jdk + unzip + which + ]; + + configureFlags = [ + "--with-libedit-include=${libedit.dev}/include" + "--with-libedit-lib=${libedit}/lib" + # "--with-berkeley-db-include=${db.dev}/include" + "--with-berkeley-db=${db}/lib" + + "--without-x" + "--disable-afs-string-to-key" + ] ++ lib.optionals (withCapNG) [ + "--with-capng" + ] ++ lib.optionals (withCJSON) [ + "--with-cjson=${cjson}" + ] ++ lib.optionals (withOpenLDAP) [ + "--with-openldap=${openldap.dev}" + ] ++ lib.optionals (withOpenLDAPAsHDBModule) [ + "--enable-hdb-openldap-module" + ] ++ lib.optionals (withSQLite3) [ + "--with-sqlite3=${sqlite.dev}" + ]; + + # (check-ldap) slapd resides within ${openldap}/libexec, + # which is not part of $PATH by default. + # (check-ldap) prepending ${openldap}/bin to the path to avoid + # using the default installation of openldap on unsandboxed darwin systems, + # which does not support the new mdb backend at the moment (2024-01-13). + # (check-ldap) the bdb backend got deprecated in favour of mdb in openldap 2.5.0, + # but the heimdal tests still seem to expect bdb as the openldap backend. + # This might be fixed upstream in a future update. + patchPhase = '' + runHook prePatch + + substituteInPlace tests/ldap/slapd-init.in \ + --replace 'SCHEMA_PATHS="' 'SCHEMA_PATHS="${openldap}/etc/schema ' + substituteInPlace tests/ldap/check-ldap.in \ + --replace 'PATH=' 'PATH=${openldap}/libexec:${openldap}/bin:' + substituteInPlace tests/ldap/slapd.conf \ + --replace 'database bdb' 'database mdb' + + runHook postPatch + ''; + + # (test_cc) heimdal uses librokens implementation of `secure_getenv` on darwin, + # which expects either USER or LOGNAME to be set. + preCheck = lib.optionalString (stdenv.isDarwin) '' + export USER=nix-builder + ''; + + # We need to build hcrypt for applications like samba + postBuild = '' + (cd include/hcrypto; make -j $NIX_BUILD_CORES) + (cd lib/hcrypto; make -j $NIX_BUILD_CORES) + ''; + + postInstall = '' + # Install hcrypto + (cd include/hcrypto; make -j $NIX_BUILD_CORES install) + (cd lib/hcrypto; make -j $NIX_BUILD_CORES install) + + mkdir -p $dev/bin + mv $out/bin/krb5-config $dev/bin/ + + # asn1 compilers, move them to $dev + mv $out/libexec/heimdal/* $dev/bin + rmdir $out/libexec/heimdal + + cp include/heim_threads.h $dev/include + + # compile_et is needed for cross-compiling this package and samba + mv lib/com_err/.libs/compile_et $dev/bin + ''; + + # Issues with hydra + # In file included from hxtool.c:34:0: + # hx_locl.h:67:25: fatal error: pkcs10_asn1.h: No such file or directory + #enableParallelBuilding = true; + + passthru = { + implementation = "heimdal"; + tests.nixos = nixosTests.kerberos.heimdal; + }; + + meta = with lib; { + homepage = "https://www.heimdal.software"; + changelog = "https://github.com/heimdal/heimdal/releases"; + description = "An implementation of Kerberos 5 (and some more stuff)"; + license = licenses.bsd3; + platforms = platforms.unix; + maintainers = with maintainers; [ h7x4 ]; + }; +} diff --git a/hosts/buskerud/containers/salsa/services/heimdal/package2.nix b/hosts/buskerud/containers/salsa/services/heimdal/package2.nix new file mode 100644 index 0000000..ff211b6 --- /dev/null +++ b/hosts/buskerud/containers/salsa/services/heimdal/package2.nix @@ -0,0 +1,178 @@ +{ lib +, stdenv +, fetchFromGitHub +, autoreconfHook +, pkg-config +, python3 +, perl +, bison +, flex +, texinfo +, perlPackages + +, openldap +, libcap_ng +, sqlite +, openssl +, db +, libedit +, pam +, krb5 +, libmicrohttpd +, cjson + +, CoreFoundation +, Security +, SystemConfiguration + +, curl +, jdk +, unzip +, which + +, nixosTests + +, withCJSON ? true +, withCapNG ? stdenv.isLinux +# libmicrohttpd should theoretically work for darwin as well, but something is broken. +# It affects tests check-bx509d and check-httpkadmind. +, withMicroHTTPD ? stdenv.isLinux +, withOpenLDAP ? true +, withOpenLDAPAsHDBModule ? false +, withOpenSSL ? true +, withSQLite3 ? true +}: + +assert lib.assertMsg (withOpenLDAPAsHDBModule -> withOpenLDAP) '' + OpenLDAP needs to be enabled in order to build the OpenLDAP HDB Module. +''; + +stdenv.mkDerivation { + pname = "heimdal"; + version = "7.8.0-unstable-2023-11-29"; + + src = fetchFromGitHub { + owner = "heimdal"; + repo = "heimdal"; + rev = "3253c49544eacb33d5ad2f6f919b0696e5aab794"; + hash = "sha256-uljzQBzXrZCZjcIWfioqHN8YsbUUNy14Vo+A3vZIXzM="; + }; + + outputs = [ "out" "dev" "man" "info" ]; + + nativeBuildInputs = [ + autoreconfHook + pkg-config + python3 + perl + bison + flex + texinfo + ] + ++ (with perlPackages; [ JSON ]); + + buildInputs = [ db libedit pam ] + ++ lib.optionals (stdenv.isDarwin) [ CoreFoundation Security SystemConfiguration ] + ++ lib.optionals (withCJSON) [ cjson ] + ++ lib.optionals (withCapNG) [ libcap_ng ] + ++ lib.optionals (withMicroHTTPD) [ libmicrohttpd ] + ++ lib.optionals (withOpenLDAP) [ openldap ] + ++ lib.optionals (withOpenSSL) [ openssl ] + ++ lib.optionals (withSQLite3) [ sqlite ]; + + doCheck = true; + nativeCheckInputs = [ + curl + jdk + unzip + which + ]; + + configureFlags = [ + "--with-libedit-include=${libedit.dev}/include" + "--with-libedit-lib=${libedit}/lib" + "--with-berkeley-db-include=${db.dev}/include" + "--with-berkeley-db" + + "--without-x" + "--disable-afs-string-to-key" + ] ++ lib.optionals (withCapNG) [ + "--with-capng" + ] ++ lib.optionals (withCJSON) [ + "--with-cjson=${cjson}" + ] ++ lib.optionals (withOpenLDAP) [ + "--with-openldap=${openldap.dev}" + ] ++ lib.optionals (withOpenLDAPAsHDBModule) [ + "--enable-hdb-openldap-module" + ] ++ lib.optionals (withSQLite3) [ + "--with-sqlite3=${sqlite.dev}" + ]; + + # (check-ldap) slapd resides within ${openldap}/libexec, + # which is not part of $PATH by default. + # (check-ldap) prepending ${openldap}/bin to the path to avoid + # using the default installation of openldap on unsandboxed darwin systems, + # which does not support the new mdb backend at the moment (2024-01-13). + # (check-ldap) the bdb backend got deprecated in favour of mdb in openldap 2.5.0, + # but the heimdal tests still seem to expect bdb as the openldap backend. + # This might be fixed upstream in a future update. + patchPhase = '' + runHook prePatch + + substituteInPlace tests/ldap/slapd-init.in \ + --replace 'SCHEMA_PATHS="' 'SCHEMA_PATHS="${openldap}/etc/schema ' + substituteInPlace tests/ldap/check-ldap.in \ + --replace 'PATH=' 'PATH=${openldap}/libexec:${openldap}/bin:' + substituteInPlace tests/ldap/slapd.conf \ + --replace 'database bdb' 'database mdb' + + runHook postPatch + ''; + + # (test_cc) heimdal uses librokens implementation of `secure_getenv` on darwin, + # which expects either USER or LOGNAME to be set. + preCheck = lib.optionalString (stdenv.isDarwin) '' + export USER=nix-builder + ''; + + # We need to build hcrypt for applications like samba + postBuild = '' + (cd include/hcrypto; make -j $NIX_BUILD_CORES) + (cd lib/hcrypto; make -j $NIX_BUILD_CORES) + ''; + + postInstall = '' + # Install hcrypto + (cd include/hcrypto; make -j $NIX_BUILD_CORES install) + (cd lib/hcrypto; make -j $NIX_BUILD_CORES install) + + mkdir -p $dev/bin + mv $out/bin/krb5-config $dev/bin/ + + # asn1 compilers, move them to $dev + mv $out/libexec/heimdal/* $dev/bin + rmdir $out/libexec/heimdal + + # compile_et is needed for cross-compiling this package and samba + mv lib/com_err/.libs/compile_et $dev/bin + ''; + + # Issues with hydra + # In file included from hxtool.c:34:0: + # hx_locl.h:67:25: fatal error: pkcs10_asn1.h: No such file or directory + #enableParallelBuilding = true; + + passthru = { + implementation = "heimdal"; + tests.nixos = nixosTests.kerberos.heimdal; + }; + + meta = with lib; { + homepage = "https://www.heimdal.software"; + changelog = "https://github.com/heimdal/heimdal/releases"; + description = "An implementation of Kerberos 5 (and some more stuff)"; + license = licenses.bsd3; + platforms = platforms.unix; + maintainers = with maintainers; [ h7x4 ]; + }; +} diff --git a/hosts/buskerud/containers/salsa/services/openldap.nix b/hosts/buskerud/containers/salsa/services/openldap.nix new file mode 100644 index 0000000..4e672a0 --- /dev/null +++ b/hosts/buskerud/containers/salsa/services/openldap.nix @@ -0,0 +1,115 @@ +{ config, pkgs, lib, ... }: +{ + services.openldap = let + dn = "dc=kerberos,dc=pvv,dc=ntnu,dc=no"; + cfg = config.services.openldap; + in { + enable = true; + + # NOTE: this is a custom build of openldap with support for + # perl and kerberos. + package = pkgs.openldap.overrideAttrs (prev: { + # https://github.com/openldap/openldap/blob/master/configure + configureFlags = prev.configureFlags ++ [ + # Connect to slapd via UNIX socket + "--enable-local" + # Cyrus SASL + "--enable-spasswd" + # Reverse hostname lookups + "--enable-rlookups" + # perl + "--enable-perl" + ]; + + buildInputs = prev.buildInputs ++ (with pkgs; [ + perl + config.security.krb5.package + ]); + + extraContribModules = prev.extraContribModules ++ [ + # https://git.openldap.org/openldap/openldap/-/tree/master/contrib/slapd-modules + "smbk5pwd" + ]; + }); + + settings = { + attrs = { + olcLogLevel = [ "stats" "config" "args" ]; + + # olcAuthzRegexp = '' + # gidNumber=.*\\\+uidNumber=0,cn=peercred,cn=external,cn=auth + # "uid=heimdal,${dn2}" + # ''; + + # olcSaslSecProps = "minssf=0"; + }; + + children = { + "cn=schema".includes = let + # NOTE: needed for smbk5pwd.so module + # schemaToLdif = name: path: pkgs.runCommandNoCC name { + # buildInputs = with pkgs; [ schema2ldif ]; + # } '' + # schema2ldif "${path}" > $out + # ''; + + # hdb-ldif = schemaToLdif "hdb.ldif" "${pkgs.heimdal.src}/lib/hdb/hdb.schema"; + # samba-ldif = schemaToLdif "samba.ldif" "${pkgs.heimdal.src}/tests/ldap/samba.schema"; + in [ + "${cfg.package}/etc/schema/core.ldif" + "${cfg.package}/etc/schema/cosine.ldif" + "${cfg.package}/etc/schema/nis.ldif" + "${cfg.package}/etc/schema/inetorgperson.ldif" + # "${hdb-ldif}" + # "${samba-ldif}" + ]; + + # NOTE: installation of smbk5pwd.so module + # https://git.openldap.org/openldap/openldap/-/tree/master/contrib/slapd-modules/smbk5pwd + # "cn=module{0}".attrs = { + # objectClass = [ "olcModuleList" ]; + # olcModuleLoad = [ "${cfg.package}/lib/modules/smbk5pwd.so" ]; + # }; + + # NOTE: activation of smbk5pwd.so module for {1}mdb + # "olcOverlay={0}smbk5pwd,olcDatabase={1}mdb".attrs = { + # objectClass = [ "olcOverlayConfig" "olcSmbK5PwdConfig" ]; + # olcOverlay = "{0}smbk5pwd"; + # olcSmbK5PwdEnable = [ "krb5" "samba" ]; + # olcSmbK5PwdMustChange = toString (60 * 60 * 24 * 30); + # }; + + "olcDatabase={1}mdb".attrs = { + objectClass = [ "olcDatabaseConfig" "olcMdbConfig" ]; + + olcDatabase = "{1}mdb"; + + olcSuffix = dn; + + # TODO: PW is supposed to be a secret, but it's probably fine for testing + olcRootDN = "cn=admin,${dn}"; + olcRootPW.path = pkgs.writeText "olcRootPW" "pass"; + + olcDbDirectory = "/var/lib/openldap/test-db"; + olcDbIndex = "objectClass eq"; + + olcAccess = [ + ''{0}to attrs=userPassword,shadowLastChange + by dn.exact=cn=admin,${dn} write + by self write + by anonymous auth + by * none'' + + ''{1}to dn.base="" + by * read'' + + /* allow read on anything else */ + # ''{2}to * + # by cn=admin,${dn} write by dn.exact=gidNumber=0+uidNumber=0+cn=peercred,cn=external write + # by * read'' + ]; + }; + }; + }; + }; +} diff --git a/hosts/buskerud/containers/salsa/services/saslauthd.nix b/hosts/buskerud/containers/salsa/services/saslauthd.nix new file mode 100644 index 0000000..19174f2 --- /dev/null +++ b/hosts/buskerud/containers/salsa/services/saslauthd.nix @@ -0,0 +1,14 @@ +{ ... }: +{ + # TODO: This is seemingly required for openldap to authenticate + # against kerberos, but I have no idea how to configure it as + # such. Does it need a keytab? There's a binary "testsaslauthd" + # that follows with `pkgs.cyrus_sasl` that might be useful. + services.saslauthd = { + enable = true; + mechanism = "kerberos5"; + # config = '' + + # ''; + }; +}