diff --git a/nixos/modules/services/databases/openldap.nix b/nixos/modules/services/databases/openldap.nix index 2c1e25d430840..c7880393f3d00 100644 --- a/nixos/modules/services/databases/openldap.nix +++ b/nixos/modules/services/databases/openldap.nix @@ -5,7 +5,14 @@ let cfg = config.services.openldap; legacyOptions = [ "rootpwFile" "suffix" "dataDir" "rootdn" "rootpw" ]; openldap = cfg.package; - configDir = if cfg.configDir != null then cfg.configDir else "/etc/openldap/slapd.d"; + useDefaultConfDir = cfg.configDir == null; + configDir = if cfg.configDir != null then cfg.configDir else "/var/lib/openldap/slapd.d"; + + dbSettings = filterAttrs (name: value: hasPrefix "olcDatabase=" name) cfg.settings.children; + dataDirs = mapAttrs' (_: value: nameValuePair value.attrs.olcSuffix (removePrefix "/var/lib/openldap/" value.attrs.olcDbDirectory)) + (lib.filterAttrs (_: value: value.attrs ? olcDbDirectory && hasPrefix "/var/lib/openldap/" value.attrs.olcDbDirectory) dbSettings); + declarativeDNs = attrNames cfg.declarativeContents; + additionalStateDirectories = map (sfx: "openldap/" + sfx) (attrValues dataDirs); ldapValueType = let # Can't do types.either with multiple non-overlapping submodules, so define our own @@ -76,44 +83,6 @@ let lib.flatten (lib.mapAttrsToList (name: value: attrsToLdif "${name},${dn}" value) children) ); in { - imports = let - deprecationNote = "This option is removed due to the deprecation of `slapd.conf` upstream. Please migrate to `services.openldap.settings`, see the release notes for advice with this process."; - mkDatabaseOption = old: new: - lib.mkChangedOptionModule [ "services" "openldap" old ] [ "services" "openldap" "settings" "children" ] - (config: let - database = lib.getAttrFromPath [ "services" "openldap" "database" ] config; - value = lib.getAttrFromPath [ "services" "openldap" old ] config; - in lib.setAttrByPath ([ "olcDatabase={1}${database}" "attrs" ] ++ new) value); - in [ - (lib.mkRemovedOptionModule [ "services" "openldap" "extraConfig" ] deprecationNote) - (lib.mkRemovedOptionModule [ "services" "openldap" "extraDatabaseConfig" ] deprecationNote) - - (lib.mkChangedOptionModule [ "services" "openldap" "logLevel" ] [ "services" "openldap" "settings" "attrs" "olcLogLevel" ] - (config: lib.splitString " " (lib.getAttrFromPath [ "services" "openldap" "logLevel" ] config))) - (lib.mkChangedOptionModule [ "services" "openldap" "defaultSchemas" ] [ "services" "openldap" "settings" "children" "cn=schema" "includes"] - (config: lib.optionals (lib.getAttrFromPath [ "services" "openldap" "defaultSchemas" ] config) ( - map (schema: "${openldap}/etc/schema/${schema}.ldif") [ "core" "cosine" "inetorgperson" "nis" ]))) - - (lib.mkChangedOptionModule [ "services" "openldap" "database" ] [ "services" "openldap" "settings" "children" ] - (config: let - database = lib.getAttrFromPath [ "services" "openldap" "database" ] config; - in { - "olcDatabase={1}${database}".attrs = { - # objectClass is case-insensitive, so don't need to capitalize ${database} - objectClass = [ "olcdatabaseconfig" "olc${database}config" ]; - olcDatabase = "{1}${database}"; - olcDbDirectory = lib.mkDefault "/var/db/openldap"; - }; - "cn=schema".includes = lib.mkDefault ( - map (schema: "${openldap}/etc/schema/${schema}.ldif") [ "core" "cosine" "inetorgperson" "nis" ] - ); - })) - (mkDatabaseOption "rootpwFile" [ "olcRootPW" "path" ]) - (mkDatabaseOption "suffix" [ "olcSuffix" ]) - (mkDatabaseOption "dataDir" [ "olcDbDirectory" ]) - (mkDatabaseOption "rootdn" [ "olcRootDN" ]) - (mkDatabaseOption "rootpw" [ "olcRootPW" ]) - ]; options = { services.openldap = { enable = mkOption { @@ -186,7 +155,7 @@ in { attrs = { objectClass = [ "olcDatabaseConfig" "olcMdbConfig" ]; olcDatabase = "{1}mdb"; - olcDbDirectory = "/var/db/ldap"; + olcDbDirectory = "/var/lib/openldap/db1"; olcDbIndex = [ "objectClass eq" "cn pres,eq" @@ -208,10 +177,9 @@ in { default = null; description = '' Use this config directory instead of generating one from the - settings option. Overrides all NixOS settings. If - you use this option,ensure `olcPidFile` is set to `/run/slapd/slapd.conf`. + settings option. Overrides all NixOS settings. ''; - example = "/var/db/slapd.d"; + example = "/var/lib/openldap/slapd.d"; }; declarativeContents = mkOption { @@ -225,6 +193,10 @@ in { reboot of the server. Performance-wise the database and indexes are rebuilt on each server startup, so this will slow down server startup, especially with large databases. + + Note that the DIT root of the declarative DB must be defined in + services.openldap.settings AND the olcDbDirectory + must be prefixed by "/var/lib/openldap/" ''; example = lib.literalExpression '' { @@ -251,7 +223,13 @@ in { assertions = map (opt: { assertion = ((getAttr opt cfg) != "_mkMergedOptionModule") -> (cfg.database != "_mkMergedOptionModule"); message = "Legacy OpenLDAP option `services.openldap.${opt}` requires `services.openldap.database` (use value \"mdb\" if unsure)"; - }) legacyOptions; + }) legacyOptions ++ map (dn: { + assertion = dataDirs ? "${dn}"; + message = '' + declarative DB ${dn} does not exist in "servies.openldap.settings" or it exists but the "olcDbDirectory" + is not prefixed by "/var/lib/openldap/" + ''; + }) declarativeDNs; environment.systemPackages = [ openldap ]; # Literal attributes must always be set @@ -259,7 +237,7 @@ in { attrs = { objectClass = "olcGlobal"; cn = "config"; - olcPidFile = "/run/slapd/slapd.pid"; + olcPidFile = "/run/openldap/slapd.pid"; }; children."cn=schema".attrs = { cn = "schema"; @@ -273,40 +251,35 @@ in { after = [ "network.target" ]; preStart = let settingsFile = pkgs.writeText "config.ldif" (lib.concatStringsSep "\n" (attrsToLdif "cn=config" cfg.settings)); - - dbSettings = lib.filterAttrs (name: value: lib.hasPrefix "olcDatabase=" name) cfg.settings.children; - dataDirs = lib.mapAttrs' (name: value: lib.nameValuePair value.attrs.olcSuffix value.attrs.olcDbDirectory) - (lib.filterAttrs (_: value: value.attrs ? olcDbDirectory) dbSettings); dataFiles = lib.mapAttrs (dn: contents: pkgs.writeText "${dn}.ldif" contents) cfg.declarativeContents; mkLoadScript = dn: let - dataDir = lib.escapeShellArg (getAttr dn dataDirs); + dataDir = lib.escapeShellArg ("/var/lib/openldap/" + getAttr dn dataDirs); in '' rm -rf ${dataDir}/* ${openldap}/bin/slapadd -F ${lib.escapeShellArg configDir} -b ${dn} -l ${getAttr dn dataFiles} - chown -R "${cfg.user}:${cfg.group}" ${dataDir} ''; in '' - mkdir -p /run/slapd - chown -R "${cfg.user}:${cfg.group}" /run/slapd - - mkdir -p ${lib.escapeShellArg configDir} ${lib.escapeShellArgs (lib.attrValues dataDirs)} - chown "${cfg.user}:${cfg.group}" ${lib.escapeShellArg configDir} ${lib.escapeShellArgs (lib.attrValues dataDirs)} - - ${lib.optionalString (cfg.configDir == null) ('' - rm -Rf ${configDir}/* + ${lib.optionalString useDefaultConfDir '' + rm -rf ${configDir}/* ${openldap}/bin/slapadd -F ${configDir} -bcn=config -l ${settingsFile} - '')} - chown -R "${cfg.user}:${cfg.group}" ${lib.escapeShellArg configDir} + ''} - ${lib.concatStrings (map mkLoadScript (lib.attrNames cfg.declarativeContents))} + ${lib.concatStrings (map mkLoadScript declarativeDNs)} ${openldap}/bin/slaptest -u -F ${lib.escapeShellArg configDir} ''; serviceConfig = { + User = cfg.user; + Group = cfg.group; + Type = "forking"; ExecStart = lib.escapeShellArgs ([ - "${openldap}/libexec/slapd" "-u" cfg.user "-g" cfg.group "-F" configDir + "${openldap}/libexec/slapd" "-F" configDir "-h" (lib.concatStringsSep " " cfg.urlList) ]); - Type = "forking"; + StateDirectory = [ "openldap/slapd.d" ] ++ additionalStateDirectories; + StateDirectoryMode = "700"; + RuntimeDirectory = "openldap"; + AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ]; + CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ]; PIDFile = cfg.settings.attrs.olcPidFile; }; }; diff --git a/nixos/tests/openldap.nix b/nixos/tests/openldap.nix index f1a39ad7dde2f..b077838b4de56 100644 --- a/nixos/tests/openldap.nix +++ b/nixos/tests/openldap.nix @@ -42,7 +42,7 @@ in { attrs = { objectClass = [ "olcDatabaseConfig" "olcMdbConfig" ]; olcDatabase = "{1}mdb"; - olcDbDirectory = "/var/db/openldap"; + olcDbDirectory = "/var/lib/openldap/current"; olcSuffix = "dc=example"; olcRootDN = { # cn=root,dc=example @@ -60,25 +60,6 @@ in { }; }) { inherit pkgs system; }; - # Old-style configuration - oldOptions = import ./make-test-python.nix ({ pkgs, ... }: { - inherit testScript; - name = "openldap"; - - machine = { pkgs, ... }: { - services.openldap = { - enable = true; - logLevel = "stats acl"; - defaultSchemas = true; - database = "mdb"; - suffix = "dc=example"; - rootdn = "cn=root,dc=example"; - rootpw = "notapassword"; - declarativeContents."dc=example" = dbContents; - }; - }; - }) { inherit system pkgs; }; - # Manually managed configDir, for example if dynamic config is essential manualConfigDir = import ./make-test-python.nix ({ pkgs, ... }: { name = "openldap"; @@ -97,7 +78,7 @@ in { cn: config objectClass: olcGlobal olcLogLevel: stats - olcPidFile: /run/slapd/slapd.pid + olcPidFile: /run/openldap/slapd.pid dn: cn=schema,cn=config cn: schema