diff --git a/nixos/modules/security/auditd.nix b/nixos/modules/security/auditd.nix index 45ea1d9b2af0..fb35ad35aebd 100644 --- a/nixos/modules/security/auditd.nix +++ b/nixos/modules/security/auditd.nix @@ -4,16 +4,107 @@ pkgs, ... }: +let + cfg = config.security.auditd; + settingsType = + with lib.types; + nullOr (oneOf [ + bool + nonEmptyStr + path + int + ]); + + prepareConfigValue = + v: + if lib.isBool v then + (if v then "yes" else "no") + else if lib.isList v then + lib.concatStringsSep " " (map prepareConfigValue v) + else + builtins.toString v; + prepareConfigText = + conf: + lib.concatLines ( + lib.mapAttrsToList (k: v: if v == null then "#${k} =" else "${k} = ${prepareConfigValue v}") conf + ); +in { - options.security.auditd.enable = lib.mkEnableOption "the Linux Audit daemon"; + options.security.auditd = { + enable = lib.mkEnableOption "the Linux Audit daemon"; + + settings = lib.mkOption { + type = lib.types.submodule { + freeformType = lib.types.attrsOf settingsType; + options = { + # space_left needs to be larger than admin_space_left, yet they default to be the same if left open. + space_left = lib.mkOption { + type = lib.types.either lib.types.int (lib.types.strMatching "[0-9]+%"); + default = 75; + description = '' + If the free space in the filesystem containing log_file drops below this value, the audit daemon takes the action specified by + {option}`space_left_action`. If the value of {option}`space_left` is specified as a whole number, it is interpreted as an absolute size in mebibytes + (MiB). If the value is specified as a number between 1 and 99 followed by a percentage sign (e.g., 5%), the audit daemon calculates + the absolute size in megabytes based on the size of the filesystem containing {option}`log_file`. (E.g., if the filesystem containing + {option}`log_file` is 2 gibibytes in size, and {option}`space_left` is set to 25%, then the audit daemon sets {option}`space_left` to approximately 500 mebibytes. + + ::: {.note} + This calculation is performed when the audit daemon starts, so if you resize the filesystem containing {option}`log_file` while the + audit daemon is running, you should send the audit daemon SIGHUP to re-read the configuration file and recalculate the correct per‐ + centage. + ::: + ''; + }; + admin_space_left = lib.mkOption { + type = lib.types.either lib.types.int (lib.types.strMatching "[0-9]+%"); + default = 50; + description = '' + This is a numeric value in mebibytes (MiB) that tells the audit daemon when to perform a configurable action because the system is running + low on disk space. This should be considered the last chance to do something before running out of disk space. The numeric value for + this parameter should be lower than the number for {option}`space_left`. You may also append a percent sign (e.g. 1%) to the number to have + the audit daemon calculate the number based on the disk partition size. + ''; + }; + }; + }; + + default = { }; + description = "auditd configuration file contents. See {auditd.conf} for supported values."; + }; + }; + + config = lib.mkIf cfg.enable { + assertions = [ + { + assertion = + let + cfg' = cfg.settings; + in + ( + (lib.isInt cfg'.space_left && lib.isInt cfg'.admin_space_left) + -> cfg'.space_left > cfg'.admin_space_left + ) + && ( + let + get_percent = s: lib.toInt (lib.strings.removeSuffix "%" s); + in + (lib.isString cfg'.space_left && lib.isString cfg'.admin_space_left) + -> (get_percent cfg'.space_left) > (get_percent cfg'.admin_space_left) + ); + message = "`security.auditd.settings.space_left` must be larger than `security.auditd.settings.admin_space_left`"; + } + ]; - config = lib.mkIf config.security.auditd.enable { # Starting auditd should also enable loading the audit rules.. security.audit.enable = lib.mkDefault true; environment.systemPackages = [ pkgs.audit ]; + environment.etc = { + "audit/auditd.conf".text = prepareConfigText cfg.settings; + }; + systemd.services.auditd = { description = "Security Audit Logging Service"; documentation = [ "man:auditd(8)" ];