at 21.11-pre 9.3 kB view raw
1{ config, lib, pkgs, ... }: 2 3with lib; 4 5let 6 cfg = config.services.privacyidea; 7 8 uwsgi = pkgs.uwsgi.override { plugins = [ "python3" ]; }; 9 python = uwsgi.python3; 10 penv = python.withPackages (ps: [ ps.privacyidea ]); 11 logCfg = pkgs.writeText "privacyidea-log.cfg" '' 12 [formatters] 13 keys=detail 14 15 [handlers] 16 keys=stream 17 18 [formatter_detail] 19 class=privacyidea.lib.log.SecureFormatter 20 format=[%(asctime)s][%(process)d][%(thread)d][%(levelname)s][%(name)s:%(lineno)d] %(message)s 21 22 [handler_stream] 23 class=StreamHandler 24 level=NOTSET 25 formatter=detail 26 args=(sys.stdout,) 27 28 [loggers] 29 keys=root,privacyidea 30 31 [logger_privacyidea] 32 handlers=stream 33 qualname=privacyidea 34 level=INFO 35 36 [logger_root] 37 handlers=stream 38 level=ERROR 39 ''; 40 41 piCfgFile = pkgs.writeText "privacyidea.cfg" '' 42 SUPERUSER_REALM = [ '${concatStringsSep "', '" cfg.superuserRealm}' ] 43 SQLALCHEMY_DATABASE_URI = 'postgresql:///privacyidea' 44 SECRET_KEY = '${cfg.secretKey}' 45 PI_PEPPER = '${cfg.pepper}' 46 PI_ENCFILE = '${cfg.encFile}' 47 PI_AUDIT_KEY_PRIVATE = '${cfg.auditKeyPrivate}' 48 PI_AUDIT_KEY_PUBLIC = '${cfg.auditKeyPublic}' 49 PI_LOGCONFIG = '${logCfg}' 50 ${cfg.extraConfig} 51 ''; 52 53in 54 55{ 56 options = { 57 services.privacyidea = { 58 enable = mkEnableOption "PrivacyIDEA"; 59 60 environmentFile = mkOption { 61 type = types.nullOr types.path; 62 default = null; 63 example = "/root/privacyidea.env"; 64 description = '' 65 File to load as environment file. Environment variables 66 from this file will be interpolated into the config file 67 using <package>envsubst</package> which is helpful for specifying 68 secrets: 69 <programlisting> 70 { <xref linkend="opt-services.privacyidea.secretKey" /> = "$SECRET"; } 71 </programlisting> 72 73 The environment-file can now specify the actual secret key: 74 <programlisting> 75 SECRET=veryverytopsecret 76 </programlisting> 77 ''; 78 }; 79 80 stateDir = mkOption { 81 type = types.str; 82 default = "/var/lib/privacyidea"; 83 description = '' 84 Directory where all PrivacyIDEA files will be placed by default. 85 ''; 86 }; 87 88 superuserRealm = mkOption { 89 type = types.listOf types.str; 90 default = [ "super" "administrators" ]; 91 description = '' 92 The realm where users are allowed to login as administrators. 93 ''; 94 }; 95 96 secretKey = mkOption { 97 type = types.str; 98 example = "t0p s3cr3t"; 99 description = '' 100 This is used to encrypt the auth_token. 101 ''; 102 }; 103 104 pepper = mkOption { 105 type = types.str; 106 example = "Never know..."; 107 description = '' 108 This is used to encrypt the admin passwords. 109 ''; 110 }; 111 112 encFile = mkOption { 113 type = types.str; 114 default = "${cfg.stateDir}/enckey"; 115 description = '' 116 This is used to encrypt the token data and token passwords 117 ''; 118 }; 119 120 auditKeyPrivate = mkOption { 121 type = types.str; 122 default = "${cfg.stateDir}/private.pem"; 123 description = '' 124 Private Key for signing the audit log. 125 ''; 126 }; 127 128 auditKeyPublic = mkOption { 129 type = types.str; 130 default = "${cfg.stateDir}/public.pem"; 131 description = '' 132 Public key for checking signatures of the audit log. 133 ''; 134 }; 135 136 adminPasswordFile = mkOption { 137 type = types.path; 138 description = "File containing password for the admin user"; 139 }; 140 141 adminEmail = mkOption { 142 type = types.str; 143 example = "admin@example.com"; 144 description = "Mail address for the admin user"; 145 }; 146 147 extraConfig = mkOption { 148 type = types.lines; 149 default = ""; 150 description = '' 151 Extra configuration options for pi.cfg. 152 ''; 153 }; 154 155 user = mkOption { 156 type = types.str; 157 default = "privacyidea"; 158 description = "User account under which PrivacyIDEA runs."; 159 }; 160 161 group = mkOption { 162 type = types.str; 163 default = "privacyidea"; 164 description = "Group account under which PrivacyIDEA runs."; 165 }; 166 167 ldap-proxy = { 168 enable = mkEnableOption "PrivacyIDEA LDAP Proxy"; 169 170 configFile = mkOption { 171 type = types.path; 172 default = ""; 173 description = '' 174 Path to PrivacyIDEA LDAP Proxy configuration (proxy.ini). 175 ''; 176 }; 177 178 user = mkOption { 179 type = types.str; 180 default = "pi-ldap-proxy"; 181 description = "User account under which PrivacyIDEA LDAP proxy runs."; 182 }; 183 184 group = mkOption { 185 type = types.str; 186 default = "pi-ldap-proxy"; 187 description = "Group account under which PrivacyIDEA LDAP proxy runs."; 188 }; 189 }; 190 }; 191 }; 192 193 config = mkMerge [ 194 195 (mkIf cfg.enable { 196 197 environment.systemPackages = [ python.pkgs.privacyidea ]; 198 199 services.postgresql.enable = mkDefault true; 200 201 systemd.services.privacyidea = let 202 piuwsgi = pkgs.writeText "uwsgi.json" (builtins.toJSON { 203 uwsgi = { 204 plugins = [ "python3" ]; 205 pythonpath = "${penv}/${uwsgi.python3.sitePackages}"; 206 socket = "/run/privacyidea/socket"; 207 uid = cfg.user; 208 gid = cfg.group; 209 chmod-socket = 770; 210 chown-socket = "${cfg.user}:nginx"; 211 chdir = cfg.stateDir; 212 wsgi-file = "${penv}/etc/privacyidea/privacyideaapp.wsgi"; 213 processes = 4; 214 harakiri = 60; 215 reload-mercy = 8; 216 stats = "/run/privacyidea/stats.socket"; 217 max-requests = 2000; 218 limit-as = 1024; 219 reload-on-as = 512; 220 reload-on-rss = 256; 221 no-orphans = true; 222 vacuum = true; 223 }; 224 }); 225 in { 226 wantedBy = [ "multi-user.target" ]; 227 after = [ "postgresql.service" ]; 228 path = with pkgs; [ openssl ]; 229 environment.PRIVACYIDEA_CONFIGFILE = "${cfg.stateDir}/privacyidea.cfg"; 230 preStart = let 231 pi-manage = "${pkgs.sudo}/bin/sudo -u privacyidea -HE ${penv}/bin/pi-manage"; 232 pgsu = config.services.postgresql.superUser; 233 psql = config.services.postgresql.package; 234 in '' 235 mkdir -p ${cfg.stateDir} /run/privacyidea 236 chown ${cfg.user}:${cfg.group} -R ${cfg.stateDir} /run/privacyidea 237 umask 077 238 ${lib.getBin pkgs.envsubst}/bin/envsubst -o ${cfg.stateDir}/privacyidea.cfg \ 239 -i "${piCfgFile}" 240 chown ${cfg.user}:${cfg.group} ${cfg.stateDir}/privacyidea.cfg 241 if ! test -e "${cfg.stateDir}/db-created"; then 242 ${pkgs.sudo}/bin/sudo -u ${pgsu} ${psql}/bin/createuser --no-superuser --no-createdb --no-createrole ${cfg.user} 243 ${pkgs.sudo}/bin/sudo -u ${pgsu} ${psql}/bin/createdb --owner ${cfg.user} privacyidea 244 ${pi-manage} create_enckey 245 ${pi-manage} create_audit_keys 246 ${pi-manage} createdb 247 ${pi-manage} admin add admin -e ${cfg.adminEmail} -p "$(cat ${cfg.adminPasswordFile})" 248 ${pi-manage} db stamp head -d ${penv}/lib/privacyidea/migrations 249 touch "${cfg.stateDir}/db-created" 250 chmod g+r "${cfg.stateDir}/enckey" "${cfg.stateDir}/private.pem" 251 fi 252 ${pi-manage} db upgrade -d ${penv}/lib/privacyidea/migrations 253 ''; 254 serviceConfig = { 255 Type = "notify"; 256 ExecStart = "${uwsgi}/bin/uwsgi --json ${piuwsgi}"; 257 ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; 258 EnvironmentFile = lib.mkIf (cfg.environmentFile != null) cfg.environmentFile; 259 ExecStop = "${pkgs.coreutils}/bin/kill -INT $MAINPID"; 260 NotifyAccess = "main"; 261 KillSignal = "SIGQUIT"; 262 }; 263 }; 264 265 users.users.privacyidea = mkIf (cfg.user == "privacyidea") { 266 group = cfg.group; 267 isSystemUser = true; 268 }; 269 270 users.groups.privacyidea = mkIf (cfg.group == "privacyidea") {}; 271 }) 272 273 (mkIf cfg.ldap-proxy.enable { 274 275 systemd.services.privacyidea-ldap-proxy = let 276 ldap-proxy-env = pkgs.python2.withPackages (ps: [ ps.privacyidea-ldap-proxy ]); 277 in { 278 description = "privacyIDEA LDAP proxy"; 279 wantedBy = [ "multi-user.target" ]; 280 serviceConfig = { 281 User = cfg.ldap-proxy.user; 282 Group = cfg.ldap-proxy.group; 283 ExecStart = '' 284 ${ldap-proxy-env}/bin/twistd \ 285 --nodaemon \ 286 --pidfile= \ 287 -u ${cfg.ldap-proxy.user} \ 288 -g ${cfg.ldap-proxy.group} \ 289 ldap-proxy \ 290 -c ${cfg.ldap-proxy.configFile} 291 ''; 292 Restart = "always"; 293 }; 294 }; 295 296 users.users.pi-ldap-proxy = mkIf (cfg.ldap-proxy.user == "pi-ldap-proxy") { 297 group = cfg.ldap-proxy.group; 298 isSystemUser = true; 299 }; 300 301 users.groups.pi-ldap-proxy = mkIf (cfg.ldap-proxy.group == "pi-ldap-proxy") {}; 302 }) 303 ]; 304 305}