1{
2 config,
3 lib,
4 pkgs,
5 ...
6}:
7let
8 cfg = config.services.sssd;
9 nscd = config.services.nscd;
10
11 dataDir = "/var/lib/sssd";
12 settingsFile = "${dataDir}/sssd.conf";
13 settingsFileUnsubstituted = pkgs.writeText "${dataDir}/sssd-unsubstituted.conf" cfg.config;
14in
15{
16 options = {
17 services.sssd = {
18 enable = lib.mkEnableOption "the System Security Services Daemon";
19
20 config = lib.mkOption {
21 type = lib.types.lines;
22 description = "Contents of {file}`sssd.conf`.";
23 default = ''
24 [sssd]
25 config_file_version = 2
26 services = nss, pam
27 domains = shadowutils
28
29 [nss]
30
31 [pam]
32
33 [domain/shadowutils]
34 id_provider = proxy
35 proxy_lib_name = files
36 auth_provider = proxy
37 proxy_pam_target = sssd-shadowutils
38 proxy_fast_alias = True
39 '';
40 };
41
42 sshAuthorizedKeysIntegration = lib.mkOption {
43 type = lib.types.bool;
44 default = false;
45 description = ''
46 Whether to make sshd look up authorized keys from SSS.
47 For this to work, the `ssh` SSS service must be enabled in the sssd configuration.
48 '';
49 };
50
51 kcm = lib.mkOption {
52 type = lib.types.bool;
53 default = false;
54 description = ''
55 Whether to use SSS as a Kerberos Cache Manager (KCM).
56 Kerberos will be configured to cache credentials in SSS.
57 '';
58 };
59 environmentFile = lib.mkOption {
60 type = lib.types.nullOr lib.types.path;
61 default = null;
62 description = ''
63 Environment file as defined in {manpage}`systemd.exec(5)`.
64
65 Secrets may be passed to the service without adding them to the world-readable
66 Nix store, by specifying placeholder variables as the option value in Nix and
67 setting these variables accordingly in the environment file.
68
69 ```
70 # snippet of sssd-related config
71 [domain/LDAP]
72 ldap_default_authtok = $SSSD_LDAP_DEFAULT_AUTHTOK
73 ```
74
75 ```
76 # contents of the environment file
77 SSSD_LDAP_DEFAULT_AUTHTOK=verysecretpassword
78 ```
79 '';
80 };
81 };
82 };
83 config = lib.mkMerge [
84 (lib.mkIf cfg.enable {
85 # For `sssctl` to work.
86 environment.etc."sssd/sssd.conf".source = settingsFile;
87 environment.etc."sssd/conf.d".source = "${dataDir}/conf.d";
88
89 systemd.services.sssd = {
90 description = "System Security Services Daemon";
91 wantedBy = [ "multi-user.target" ];
92 before = [
93 "systemd-user-sessions.service"
94 "nss-user-lookup.target"
95 ];
96 after = [
97 "network-online.target"
98 "nscd.service"
99 ];
100 requires = [
101 "network-online.target"
102 "nscd.service"
103 ];
104 wants = [ "nss-user-lookup.target" ];
105 restartTriggers = [
106 config.environment.etc."nscd.conf".source
107 settingsFileUnsubstituted
108 ];
109 script = ''
110 export LDB_MODULES_PATH+="''${LDB_MODULES_PATH+:}${pkgs.ldb}/modules/ldb:${pkgs.sssd}/modules/ldb"
111 mkdir -p /var/lib/sss/{pubconf,db,mc,pipes,gpo_cache,secrets} /var/lib/sss/pipes/private /var/lib/sss/pubconf/krb5.include.d
112 ${pkgs.sssd}/bin/sssd -D -c ${settingsFile}
113 '';
114 serviceConfig = {
115 Type = "forking";
116 PIDFile = "/run/sssd.pid";
117 StateDirectory = baseNameOf dataDir;
118 # We cannot use LoadCredential here because it's not available in ExecStartPre
119 EnvironmentFile = lib.mkIf (cfg.environmentFile != null) cfg.environmentFile;
120 };
121 preStart = ''
122 mkdir -p "${dataDir}/conf.d"
123 [ -f ${settingsFile} ] && rm -f ${settingsFile}
124 old_umask=$(umask)
125 umask 0177
126 ${pkgs.envsubst}/bin/envsubst \
127 -o ${settingsFile} \
128 -i ${settingsFileUnsubstituted}
129 umask $old_umask
130 '';
131 };
132
133 system.nssModules = [ pkgs.sssd ];
134 system.nssDatabases = {
135 group = [ "sss" ];
136 passwd = [ "sss" ];
137 services = [ "sss" ];
138 shadow = [ "sss" ];
139 };
140 services.dbus.packages = [ pkgs.sssd ];
141 })
142
143 (lib.mkIf cfg.kcm {
144 systemd.services.sssd-kcm = {
145 description = "SSSD Kerberos Cache Manager";
146 requires = [ "sssd-kcm.socket" ];
147 serviceConfig = {
148 ExecStartPre = "-${pkgs.sssd}/bin/sssd --genconf-section=kcm";
149 ExecStart = "${pkgs.sssd}/libexec/sssd/sssd_kcm --uid 0 --gid 0";
150 };
151 restartTriggers = [
152 settingsFileUnsubstituted
153 ];
154 };
155 systemd.sockets.sssd-kcm = {
156 description = "SSSD Kerberos Cache Manager responder socket";
157 wantedBy = [ "sockets.target" ];
158 # Matches the default in MIT krb5 and Heimdal:
159 # https://github.com/krb5/krb5/blob/krb5-1.19.3-final/src/include/kcm.h#L43
160 listenStreams = [ "/var/run/.heim_org.h5l.kcm-socket" ];
161 };
162 security.krb5.settings.libdefaults.default_ccache_name = "KCM:";
163 })
164
165 (lib.mkIf cfg.sshAuthorizedKeysIntegration {
166 # Ugly: sshd refuses to start if a store path is given because /nix/store is group-writable.
167 # So indirect by a symlink.
168 environment.etc."ssh/authorized_keys_command" = {
169 mode = "0755";
170 text = ''
171 #!/bin/sh
172 exec ${pkgs.sssd}/bin/sss_ssh_authorizedkeys "$@"
173 '';
174 };
175 services.openssh.authorizedKeysCommand = "/etc/ssh/authorized_keys_command";
176 services.openssh.authorizedKeysCommandUser = "nobody";
177 })
178 ];
179
180 meta.maintainers = with lib.maintainers; [ bbigras ];
181}