parent
6cbdd8640a
commit
134c66b584
@ -0,0 +1,296 @@ |
||||
{ config, lib, pkgs, ... }: |
||||
|
||||
with lib; |
||||
|
||||
let |
||||
cfg = config.services.privacyidea; |
||||
|
||||
uwsgi = pkgs.uwsgi.override { plugins = [ "python3" ]; }; |
||||
python = uwsgi.python3; |
||||
penv = python.withPackages (ps: [ ps.privacyidea ]); |
||||
logCfg = pkgs.writeText "privacyidea-log.cfg" '' |
||||
[formatters] |
||||
keys=detail |
||||
|
||||
[handlers] |
||||
keys=stream |
||||
|
||||
[formatter_detail] |
||||
class=privacyidea.lib.log.SecureFormatter |
||||
format=[%(asctime)s][%(process)d][%(thread)d][%(levelname)s][%(name)s:%(lineno)d] %(message)s |
||||
|
||||
[handler_stream] |
||||
class=StreamHandler |
||||
level=NOTSET |
||||
formatter=detail |
||||
args=(sys.stdout,) |
||||
|
||||
[loggers] |
||||
keys=root,privacyidea |
||||
|
||||
[logger_privacyidea] |
||||
handlers=stream |
||||
qualname=privacyidea |
||||
level=INFO |
||||
|
||||
[logger_root] |
||||
handlers=stream |
||||
level=ERROR |
||||
''; |
||||
|
||||
piCfgFile = pkgs.writeText "privacyidea.cfg" '' |
||||
SUPERUSER_REALM = [ '${concatStringsSep "', '" cfg.superuserRealm}' ] |
||||
SQLALCHEMY_DATABASE_URI = '${cfg.databaseURI}' |
||||
SECRET_KEY = '${cfg.secretKey}' |
||||
PI_PEPPER = '${cfg.pepper}' |
||||
PI_ENCFILE = '${cfg.encFile}' |
||||
PI_AUDIT_KEY_PRIVATE = '${cfg.auditKeyPrivate}' |
||||
PI_AUDIT_KEY_PUBLIC = '${cfg.auditKeyPublic}' |
||||
PI_LOGCONFIG = '${logCfg}' |
||||
${cfg.extraConfig} |
||||
''; |
||||
|
||||
in |
||||
|
||||
{ |
||||
options = { |
||||
services.privacyidea = { |
||||
enable = mkEnableOption "PrivacyIDEA"; |
||||
|
||||
stateDir = mkOption { |
||||
type = types.str; |
||||
default = "/var/lib/privacyidea"; |
||||
description = '' |
||||
Directory where all PrivacyIDEA files will be placed by default. |
||||
''; |
||||
}; |
||||
|
||||
runDir = mkOption { |
||||
type = types.str; |
||||
default = "/run/privacyidea"; |
||||
description = '' |
||||
Directory where all PrivacyIDEA files will be placed by default. |
||||
''; |
||||
}; |
||||
|
||||
superuserRealm = mkOption { |
||||
type = types.listOf types.str; |
||||
default = [ "super" "administrators" ]; |
||||
description = '' |
||||
The realm where users are allowed to login as administrators. |
||||
''; |
||||
}; |
||||
|
||||
databaseURI = mkOption { |
||||
type = types.str; |
||||
default = "postgresql:///privacyidea"; |
||||
description = '' |
||||
Database as SQLAlchemy URI to use for PrivacyIDEA. |
||||
''; |
||||
}; |
||||
|
||||
secretKey = mkOption { |
||||
type = types.str; |
||||
example = "t0p s3cr3t"; |
||||
description = '' |
||||
This is used to encrypt the auth_token. |
||||
''; |
||||
}; |
||||
|
||||
pepper = mkOption { |
||||
type = types.str; |
||||
example = "Never know..."; |
||||
description = '' |
||||
This is used to encrypt the admin passwords. |
||||
''; |
||||
}; |
||||
|
||||
encFile = mkOption { |
||||
type = types.str; |
||||
default = "${cfg.stateDir}/enckey"; |
||||
description = '' |
||||
This is used to encrypt the token data and token passwords |
||||
''; |
||||
}; |
||||
|
||||
auditKeyPrivate = mkOption { |
||||
type = types.str; |
||||
default = "${cfg.stateDir}/private.pem"; |
||||
description = '' |
||||
Private Key for signing the audit log. |
||||
''; |
||||
}; |
||||
|
||||
auditKeyPublic = mkOption { |
||||
type = types.str; |
||||
default = "${cfg.stateDir}/public.pem"; |
||||
description = '' |
||||
Public key for checking signatures of the audit log. |
||||
''; |
||||
}; |
||||
|
||||
adminPassword = mkOption { |
||||
type = types.str; |
||||
description = "Password for the admin user"; |
||||
}; |
||||
|
||||
adminEmail = mkOption { |
||||
type = types.str; |
||||
example = "admin@example.com"; |
||||
description = "Mail address for the admin user"; |
||||
}; |
||||
|
||||
extraConfig = mkOption { |
||||
type = types.lines; |
||||
default = ""; |
||||
description = '' |
||||
Extra configuration options for pi.cfg. |
||||
''; |
||||
}; |
||||
|
||||
user = mkOption { |
||||
type = types.str; |
||||
default = "privacyidea"; |
||||
description = "User account under which PrivacyIDEA runs."; |
||||
}; |
||||
|
||||
group = mkOption { |
||||
type = types.str; |
||||
default = "privacyidea"; |
||||
description = "Group account under which PrivacyIDEA runs."; |
||||
}; |
||||
|
||||
ldap-proxy = { |
||||
enable = mkEnableOption "PrivacyIDEA LDAP Proxy"; |
||||
|
||||
configFile = mkOption { |
||||
type = types.path; |
||||
default = ""; |
||||
description = '' |
||||
Path to PrivacyIDEA LDAP Proxy configuration (proxy.ini). |
||||
''; |
||||
}; |
||||
|
||||
user = mkOption { |
||||
type = types.str; |
||||
default = "pi-ldap-proxy"; |
||||
description = "User account under which PrivacyIDEA LDAP proxy runs."; |
||||
}; |
||||
|
||||
group = mkOption { |
||||
type = types.str; |
||||
default = "pi-ldap-proxy"; |
||||
description = "Group account under which PrivacyIDEA LDAP proxy runs."; |
||||
}; |
||||
}; |
||||
}; |
||||
}; |
||||
|
||||
config = mkMerge [ |
||||
|
||||
(mkIf cfg.enable { |
||||
|
||||
environment.systemPackages = [ python.pkgs.privacyidea ]; |
||||
|
||||
services.postgresql.enable = mkDefault true; |
||||
|
||||
systemd.services.privacyidea = let |
||||
piuwsgi = pkgs.writeText "uwsgi.json" (builtins.toJSON { |
||||
uwsgi = { |
||||
plugins = [ "python3" ]; |
||||
pythonpath = "${penv}/${uwsgi.python3.sitePackages}"; |
||||
socket = "${cfg.runDir}/socket"; |
||||
uid = cfg.user; |
||||
gid = cfg.group; |
||||
chmod-socket = 770; |
||||
chown-socket = "${cfg.user}:nginx"; |
||||
chdir = cfg.stateDir; |
||||
wsgi-file = "${penv}/etc/privacyidea/privacyideaapp.wsgi"; |
||||
processes = 4; |
||||
harakiri = 60; |
||||
reload-mercy = 8; |
||||
stats = "${cfg.runDir}/stats.socket"; |
||||
max-requests = 2000; |
||||
limit-as = 1024; |
||||
reload-on-as = 512; |
||||
reload-on-rss = 256; |
||||
no-orphans = true; |
||||
vacuum = true; |
||||
}; |
||||
}); |
||||
in { |
||||
wantedBy = [ "multi-user.target" ]; |
||||
after = [ "postgresql.service" ]; |
||||
path = with pkgs; [ openssl ]; |
||||
environment.PRIVACYIDEA_CONFIGFILE = piCfgFile; |
||||
preStart = let |
||||
pi-manage = "${pkgs.sudo}/bin/sudo -u privacyidea -H PRIVACYIDEA_CONFIGFILE=${piCfgFile} ${penv}/bin/pi-manage"; |
||||
pgsu = config.services.postgresql.superUser; |
||||
psql = config.services.postgresql.package; |
||||
in '' |
||||
mkdir -p ${cfg.stateDir} ${cfg.runDir} |
||||
chown ${cfg.user}:${cfg.group} -R ${cfg.stateDir} ${cfg.runDir} |
||||
ln -sf ${piCfgFile} ${cfg.stateDir}/privacyidea.cfg |
||||
if ! test -e "${cfg.stateDir}/db-created"; then |
||||
${pkgs.sudo}/bin/sudo -u ${pgsu} ${psql}/bin/createuser --no-superuser --no-createdb --no-createrole ${cfg.user} |
||||
${pkgs.sudo}/bin/sudo -u ${pgsu} ${psql}/bin/createdb --owner ${cfg.user} privacyidea |
||||
${pi-manage} create_enckey |
||||
${pi-manage} create_audit_keys |
||||
${pi-manage} createdb |
||||
${pi-manage} admin add admin -e ${cfg.adminEmail} -p ${cfg.adminPassword} |
||||
${pi-manage} db stamp head -d ${penv}/lib/privacyidea/migrations |
||||
touch "${cfg.stateDir}/db-created" |
||||
chmod g+r "${cfg.stateDir}/enckey" "${cfg.stateDir}/private.pem" |
||||
fi |
||||
${pi-manage} db upgrade -d ${penv}/lib/privacyidea/migrations |
||||
''; |
||||
serviceConfig = { |
||||
Type = "notify"; |
||||
ExecStart = "${uwsgi}/bin/uwsgi --json ${piuwsgi}"; |
||||
ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; |
||||
ExecStop = "${pkgs.coreutils}/bin/kill -INT $MAINPID"; |
||||
NotifyAccess = "main"; |
||||
KillSignal = "SIGQUIT"; |
||||
StandardError = "syslog"; |
||||
}; |
||||
}; |
||||
|
||||
users.extraUsers.privacyidea = mkIf (cfg.user == "privacyidea") { |
||||
group = cfg.group; |
||||
}; |
||||
|
||||
users.extraGroups.privacyidea = mkIf (cfg.group == "privacyidea") {}; |
||||
}) |
||||
|
||||
(mkIf cfg.ldap-proxy.enable { |
||||
|
||||
systemd.services.privacyidea-ldap-proxy = let |
||||
ldap-proxy-env = pkgs.python2.withPackages (ps: [ ps.privacyidea-ldap-proxy ]); |
||||
in { |
||||
description = "privacyIDEA LDAP proxy"; |
||||
wantedBy = [ "multi-user.target" ]; |
||||
serviceConfig = { |
||||
User = cfg.ldap-proxy.user; |
||||
Group = cfg.ldap-proxy.group; |
||||
ExecStart = '' |
||||
${ldap-proxy-env}/bin/twistd \ |
||||
--nodaemon \ |
||||
--pidfile= \ |
||||
-u ${cfg.ldap-proxy.user} \ |
||||
-g ${cfg.ldap-proxy.group} \ |
||||
ldap-proxy \ |
||||
-c ${cfg.ldap-proxy.configFile} |
||||
''; |
||||
Restart = "always"; |
||||
}; |
||||
}; |
||||
|
||||
users.extraUsers.pi-ldap-proxy = mkIf (cfg.ldap-proxy.user == "pi-ldap-proxy") { |
||||
group = cfg.ldap-proxy.group; |
||||
}; |
||||
|
||||
users.extraGroups.pi-ldap-proxy = mkIf (cfg.ldap-proxy.group == "pi-ldap-proxy") {}; |
||||
}) |
||||
]; |
||||
|
||||
} |
@ -0,0 +1,36 @@ |
||||
# Miscellaneous small tests that don't warrant their own VM run. |
||||
|
||||
import ./make-test-python.nix ({ pkgs, ...} : rec { |
||||
name = "privacyidea"; |
||||
meta = with pkgs.stdenv.lib.maintainers; { |
||||
maintainers = [ fpletz ]; |
||||
}; |
||||
|
||||
machine = { ... }: { |
||||
virtualisation.cores = 2; |
||||
virtualisation.memorySize = 512; |
||||
|
||||
services.privacyidea = { |
||||
enable = true; |
||||
secretKey = "testing"; |
||||
pepper = "testing"; |
||||
adminPassword = "testing"; |
||||
adminEmail = "root@localhost"; |
||||
}; |
||||
services.nginx = { |
||||
enable = true; |
||||
virtualHosts."_".locations."/".extraConfig = '' |
||||
uwsgi_pass unix:/run/privacyidea/socket; |
||||
''; |
||||
}; |
||||
}; |
||||
|
||||
testScript = '' |
||||
machine.start() |
||||
machine.wait_for_unit("multi-user.target") |
||||
machine.succeed("curl --fail http://localhost | grep privacyIDEA") |
||||
machine.succeed( |
||||
"curl --fail http://localhost/auth -F username=admin -F password=testing | grep token" |
||||
) |
||||
''; |
||||
}) |
Loading…
Reference in new issue