From ecaf6aed02da7cc72721567fe85387e4bdd9948d Mon Sep 17 00:00:00 2001 From: Maximilian Bosch Date: Thu, 6 Oct 2022 11:26:13 +0200 Subject: [PATCH 1/3] nixos/privacyidea: add proper support for `privacyidea-token-janitor` `privacyidea-token-janitor`[1] is a tool which helps to automate maintenance of tokens. This is helpful to identify e.g. orphaned tokens, i.e. tokens of users that were removed or tokens that were unused for a longer period of time and apply actions to them (e.g. `disable` or `delete`). This patch adds two new things: * A wrapper for `privacyidea-token-janitor` to make sure it's executable from CLI. To achieve this, it does a `sudo(8)` into the `privacyidea`-user and sets up the environment to make sure the configuration file can be found. With that, administrators can directly invoke it from the CLI without additional steps. * An optional service is added which performs automatic cleanups of orphaned and/or unassigned tokens. Yes, the tool can do way more stuff, but I figured it's reasonable to have an automatic way to clean up tokens of users who were removed from the PI instance. Additional automation steps should probably be implemented in additional services (and are perhaps too custom to add them to this module). [1] https://privacyidea.readthedocs.io/en/v3.7/workflows_and_tools/tools/index.html --- .../modules/services/security/privacyidea.nix | 94 ++++++++++++++++++- 1 file changed, 93 insertions(+), 1 deletion(-) diff --git a/nixos/modules/services/security/privacyidea.nix b/nixos/modules/services/security/privacyidea.nix index 5cd338ebf7fe..f8f97a88d2fc 100644 --- a/nixos/modules/services/security/privacyidea.nix +++ b/nixos/modules/services/security/privacyidea.nix @@ -61,6 +61,12 @@ let (flip mapAttrs cfg.ldap-proxy.settings (const (mapAttrs (const renderValue))))); + privacyidea-token-janitor = pkgs.writeShellScriptBin "privacyidea-token-janitor" '' + exec -a privacyidea-token-janitor \ + /run/wrappers/bin/sudo -u ${cfg.user} \ + env PRIVACYIDEA_CONFIGFILE=${cfg.stateDir}/privacyidea.cfg \ + ${penv}/bin/privacyidea-token-janitor $@ + ''; in { @@ -178,6 +184,42 @@ in description = lib.mdDoc "Group account under which PrivacyIDEA runs."; }; + tokenjanitor = { + enable = mkEnableOption "automatic runs of the token janitor"; + interval = mkOption { + default = "quarterly"; + type = types.str; + description = lib.mdDoc '' + Interval in which the cleanup program is supposed to run. + See {manpage}`systemd.time(7)` for further information. + ''; + }; + action = mkOption { + type = types.enum [ "delete" "mark" "disable" "unassign" ]; + description = lib.mdDoc '' + Which action to take for matching tokens. + ''; + }; + unassigned = mkOption { + default = false; + type = types.bool; + description = lib.mdDoc '' + Whether to search for **unassigned** tokens + and apply [](#opt-services.privacyidea.tokenjanitor.action) + onto them. + ''; + }; + orphaned = mkOption { + default = true; + type = types.bool; + description = lib.mdDoc '' + Whether to search for **orphaned** tokens + and apply [](#opt-services.privacyidea.tokenjanitor.action) + onto them. + ''; + }; + }; + ldap-proxy = { enable = mkEnableOption (lib.mdDoc "PrivacyIDEA LDAP Proxy"); @@ -228,10 +270,60 @@ in (mkIf cfg.enable { - environment.systemPackages = [ pkgs.privacyidea ]; + assertions = [ + { + assertion = cfg.tokenjanitor.enable -> (cfg.tokenjanitor.orphaned || cfg.tokenjanitor.unassigned); + message = '' + privacyidea-token-janitor has no effect if neither orphaned nor unassigned tokens + are to be searched. + ''; + } + ]; + + environment.systemPackages = [ pkgs.privacyidea (hiPrio privacyidea-token-janitor) ]; services.postgresql.enable = mkDefault true; + systemd.services.privacyidea-tokenjanitor = mkIf cfg.tokenjanitor.enable { + environment.PRIVACYIDEA_CONFIGFILE = "${cfg.stateDir}/privacyidea.cfg"; + path = [ penv ]; + serviceConfig = { + CapabilityBoundingSet = [ "" ]; + ExecStart = "${pkgs.writeShellScript "pi-token-janitor" '' + ${optionalString cfg.tokenjanitor.orphaned '' + echo >&2 "Removing orphaned tokens..." + privacyidea-token-janitor find \ + --orphaned true \ + --action ${cfg.tokenjanitor.action} + ''} + ${optionalString cfg.tokenjanitor.unassigned '' + echo >&2 "Removing unassigned tokens..." + privacyidea-token-janitor find \ + --assigned false \ + --action ${cfg.tokenjanitor.action} + ''} + ''}"; + Group = cfg.group; + LockPersonality = true; + MemoryDenyWriteExecute = true; + ProtectHome = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectSystem = "strict"; + ReadWritePaths = cfg.stateDir; + Type = "oneshot"; + User = cfg.user; + WorkingDirectory = cfg.stateDir; + }; + }; + systemd.timers.privacyidea-tokenjanitor = mkIf cfg.tokenjanitor.enable { + wantedBy = [ "timers.target" ]; + timerConfig.OnCalendar = cfg.tokenjanitor.interval; + timerConfig.Persistent = true; + }; + systemd.services.privacyidea = let piuwsgi = pkgs.writeText "uwsgi.json" (builtins.toJSON { uwsgi = { From 1c7728df2a46a783023779187f6573ca9a90ad9b Mon Sep 17 00:00:00 2001 From: Maximilian Bosch Date: Thu, 6 Oct 2022 11:59:35 +0200 Subject: [PATCH 2/3] privacyidea: fix build Failing Hydra build: https://hydra.nixos.org/build/192932057 Just a small test error, workaround applied from upstream/master. --- pkgs/applications/misc/privacyidea/default.nix | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/pkgs/applications/misc/privacyidea/default.nix b/pkgs/applications/misc/privacyidea/default.nix index d7613b0c2a54..405d992576da 100644 --- a/pkgs/applications/misc/privacyidea/default.nix +++ b/pkgs/applications/misc/privacyidea/default.nix @@ -1,5 +1,5 @@ { lib, fetchFromGitHub, cacert, openssl, nixosTests -, python39 +, python39, fetchpatch }: let @@ -107,6 +107,16 @@ python3'.pkgs.buildPythonPackage rec { pydash ecdsa google-auth importlib-metadata argon2-cffi bcrypt ]; + patches = [ + # Apply https://github.com/privacyidea/privacyidea/pull/3304, fixes + # `Exceeds the limit (4300) for integer string conversion` in the tests, + # see https://hydra.nixos.org/build/192932057 + (fetchpatch { + url = "https://github.com/privacyidea/privacyidea/commit/0e28f36c0b3291a361669f4a3a77c294f4564475.patch"; + sha256 = "sha256-QqcO8bkt+I2JKce/xk2ZhzEaLZ3E4uZ4x5W9Kk0pMQQ="; + }) + ]; + passthru.tests = { inherit (nixosTests) privacyidea; }; checkInputs = with python3'.pkgs; [ openssl mock pytestCheckHook responses testfixtures ]; From 15914eba855c306a397595b83810d9894c34f41b Mon Sep 17 00:00:00 2001 From: Maximilian Bosch Date: Thu, 6 Oct 2022 13:50:31 +0200 Subject: [PATCH 3/3] nixos/privacyidea: fix manual build --- nixos/modules/services/security/privacyidea.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nixos/modules/services/security/privacyidea.nix b/nixos/modules/services/security/privacyidea.nix index f8f97a88d2fc..e446e606cad8 100644 --- a/nixos/modules/services/security/privacyidea.nix +++ b/nixos/modules/services/security/privacyidea.nix @@ -185,7 +185,7 @@ in }; tokenjanitor = { - enable = mkEnableOption "automatic runs of the token janitor"; + enable = mkEnableOption (lib.mdDoc "automatic runs of the token janitor"); interval = mkOption { default = "quarterly"; type = types.str;