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