Merge pull request #58419 from flokli/ldap-nslcd-startup

nixos/ldap: set proper User= and Group= for nslcd service
This commit is contained in:
Florian Klink 2019-03-28 14:30:14 +01:00 committed by GitHub
commit 6670b4c37d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 56 additions and 47 deletions

View File

@ -516,6 +516,13 @@
Graylog</link> for details. Graylog</link> for details.
</para> </para>
</listitem> </listitem>
<listitem>
<para>
The option <literal>users.ldap.bind.password</literal> was renamed to <literal>users.ldap.bind.passwordFile</literal>,
and needs to be readable by the <literal>nslcd</literal> user.
Same applies to the new <literal>users.ldap.daemon.rootpwmodpwFile</literal> option.
</para>
</listitem>
</itemizedlist> </itemizedlist>
</section> </section>

View File

@ -27,25 +27,29 @@ let
''; '';
}; };
nslcdConfig = { nslcdConfig = writeText "nslcd.conf" ''
target = "nslcd.conf"; uid nslcd
source = writeText "nslcd.conf" '' gid nslcd
uid nslcd uri ${cfg.server}
gid nslcd base ${cfg.base}
uri ${cfg.server} timelimit ${toString cfg.timeLimit}
base ${cfg.base} bind_timelimit ${toString cfg.bind.timeLimit}
timelimit ${toString cfg.timeLimit} ${optionalString (cfg.bind.distinguishedName != "")
bind_timelimit ${toString cfg.bind.timeLimit} "binddn ${cfg.bind.distinguishedName}" }
${optionalString (cfg.bind.distinguishedName != "") ${optionalString (cfg.daemon.rootpwmoddn != "")
"binddn ${cfg.bind.distinguishedName}" } "rootpwmoddn ${cfg.daemon.rootpwmoddn}" }
${optionalString (cfg.daemon.rootpwmoddn != "") ${optionalString (cfg.daemon.extraConfig != "") cfg.daemon.extraConfig }
"rootpwmoddn ${cfg.daemon.rootpwmoddn}" } '';
${optionalString (cfg.daemon.extraConfig != "") cfg.daemon.extraConfig }
'';
};
insertLdapPassword = !config.users.ldap.daemon.enable && # nslcd normally reads configuration from /etc/nslcd.conf.
config.users.ldap.bind.distinguishedName != ""; # this file might contain secrets. We append those at runtime,
# so redirect its location to something more temporary.
nslcdWrapped = runCommandNoCC "nslcd-wrapped" { nativeBuildInputs = [ makeWrapper ]; } ''
mkdir -p $out/bin
makeWrapper ${nss_pam_ldapd}/sbin/nslcd $out/bin/nslcd \
--set LD_PRELOAD "${pkgs.libredirect}/lib/libredirect.so" \
--set NIX_REDIRECTS "/etc/nslcd.conf=/run/nslcd/nslcd.conf"
'';
in in
@ -139,13 +143,13 @@ in
''; '';
}; };
rootpwmodpw = mkOption { rootpwmodpwFile = mkOption {
default = ""; default = "";
example = "/run/keys/nslcd.rootpwmodpw"; example = "/run/keys/nslcd.rootpwmodpw";
type = types.str; type = types.str;
description = '' description = ''
The path to a file containing the credentials with which The path to a file containing the credentials with which to bind to
to bind to the LDAP server if the root user tries to change a user's password the LDAP server if the root user tries to change a user's password.
''; '';
}; };
}; };
@ -161,7 +165,7 @@ in
''; '';
}; };
password = mkOption { passwordFile = mkOption {
default = "/etc/ldap/bind.password"; default = "/etc/ldap/bind.password";
type = types.str; type = types.str;
description = '' description = ''
@ -220,14 +224,14 @@ in
config = mkIf cfg.enable { config = mkIf cfg.enable {
environment.etc = if cfg.daemon.enable then [nslcdConfig] else [ldapConfig]; environment.etc = optional (!cfg.daemon.enable) ldapConfig;
system.activationScripts = mkIf insertLdapPassword { system.activationScripts = mkIf (!cfg.daemon.enable) {
ldap = stringAfter [ "etc" "groups" "users" ] '' ldap = stringAfter [ "etc" "groups" "users" ] ''
if test -f "${cfg.bind.password}" ; then if test -f "${cfg.bind.passwordFile}" ; then
umask 0077 umask 0077
conf="$(mktemp)" conf="$(mktemp)"
printf 'bindpw %s\n' "$(cat ${cfg.bind.password})" | printf 'bindpw %s\n' "$(cat ${cfg.bind.passwordFile})" |
cat ${ldapConfig.source} - >"$conf" cat ${ldapConfig.source} - >"$conf"
mv -fT "$conf" /etc/ldap.conf mv -fT "$conf" /etc/ldap.conf
fi fi
@ -251,7 +255,6 @@ in
}; };
systemd.services = mkIf cfg.daemon.enable { systemd.services = mkIf cfg.daemon.enable {
nslcd = { nslcd = {
wantedBy = [ "multi-user.target" ]; wantedBy = [ "multi-user.target" ];
@ -259,32 +262,32 @@ in
umask 0077 umask 0077
conf="$(mktemp)" conf="$(mktemp)"
{ {
cat ${nslcdConfig.source} cat ${nslcdConfig}
test -z '${cfg.bind.distinguishedName}' -o ! -f '${cfg.bind.password}' || test -z '${cfg.bind.distinguishedName}' -o ! -f '${cfg.bind.passwordFile}' ||
printf 'bindpw %s\n' "$(cat '${cfg.bind.password}')" printf 'bindpw %s\n' "$(cat '${cfg.bind.passwordFile}')"
test -z '${cfg.daemon.rootpwmoddn}' -o ! -f '${cfg.daemon.rootpwmodpw}' || test -z '${cfg.daemon.rootpwmoddn}' -o ! -f '${cfg.daemon.rootpwmodpwFile}' ||
printf 'rootpwmodpw %s\n' "$(cat '${cfg.daemon.rootpwmodpw}')" printf 'rootpwmodpw %s\n' "$(cat '${cfg.daemon.rootpwmodpwFile}')"
} >"$conf" } >"$conf"
mv -fT "$conf" /etc/nslcd.conf mv -fT "$conf" /run/nslcd/nslcd.conf
''; '';
restartTriggers = [ "/run/nslcd/nslcd.conf" ];
# NOTE: because one cannot pass a custom config path to `nslcd`
# (which is only able to use `/etc/nslcd.conf`)
# changes in `nslcdConfig` won't change `serviceConfig`,
# and thus won't restart `nslcd`.
# Therefore `restartTriggers` is used on `/etc/nslcd.conf`.
restartTriggers = [ nslcdConfig.source ];
serviceConfig = { serviceConfig = {
ExecStart = "${nss_pam_ldapd}/sbin/nslcd"; ExecStart = "${nslcdWrapped}/bin/nslcd";
Type = "forking"; Type = "forking";
PIDFile = "/run/nslcd/nslcd.pid";
Restart = "always"; Restart = "always";
User = "nslcd";
Group = "nslcd";
RuntimeDirectory = [ "nslcd" ]; RuntimeDirectory = [ "nslcd" ];
PIDFile = "/run/nslcd/nslcd.pid";
}; };
}; };
}; };
}; };
imports =
[ (mkRenamedOptionModule [ "users" "ldap" "bind" "password"] [ "users" "ldap" "bind" "passwordFile"])
];
} }

View File

@ -28,20 +28,19 @@ let
users.ldap.daemon = { users.ldap.daemon = {
enable = useDaemon; enable = useDaemon;
rootpwmoddn = "cn=admin,${dbSuffix}"; rootpwmoddn = "cn=admin,${dbSuffix}";
rootpwmodpw = "/etc/nslcd.rootpwmodpw"; rootpwmodpwFile = "/etc/nslcd.rootpwmodpw";
}; };
# NOTE: password stored in clear in Nix's store, but this is a test.
environment.etc."nslcd.rootpwmodpw".source = pkgs.writeText "rootpwmodpw" dbAdminPwd;
users.ldap.loginPam = true; users.ldap.loginPam = true;
users.ldap.nsswitch = true; users.ldap.nsswitch = true;
users.ldap.server = "ldap://server"; users.ldap.server = "ldap://server";
users.ldap.base = "ou=posix,${dbSuffix}"; users.ldap.base = "ou=posix,${dbSuffix}";
users.ldap.bind = { users.ldap.bind = {
distinguishedName = "cn=admin,${dbSuffix}"; distinguishedName = "cn=admin,${dbSuffix}";
password = "/etc/ldap/bind.password"; passwordFile = "/etc/ldap/bind.password";
}; };
# NOTE: password stored in clear in Nix's store, but this is a test. # NOTE: passwords stored in clear in Nix's store, but this is a test.
environment.etc."ldap/bind.password".source = pkgs.writeText "password" dbAdminPwd; environment.etc."ldap/bind.password".source = pkgs.writeText "password" dbAdminPwd;
environment.etc."nslcd.rootpwmodpw".source = pkgs.writeText "rootpwmodpw" dbAdminPwd;
}; };
in in