at 23.11-pre 6.6 kB view raw
1{ config, lib, pkgs, ... }: 2 3with lib; 4 5let 6 cfg = config.services.logcheck; 7 8 defaultRules = pkgs.runCommand "logcheck-default-rules" { preferLocalBuild = true; } '' 9 cp -prd ${pkgs.logcheck}/etc/logcheck $out 10 chmod u+w $out 11 rm -r $out/logcheck.* 12 ''; 13 14 rulesDir = pkgs.symlinkJoin 15 { name = "logcheck-rules-dir"; 16 paths = ([ defaultRules ] ++ cfg.extraRulesDirs); 17 }; 18 19 configFile = pkgs.writeText "logcheck.conf" cfg.config; 20 21 logFiles = pkgs.writeText "logcheck.logfiles" cfg.files; 22 23 flags = "-r ${rulesDir} -c ${configFile} -L ${logFiles} -${levelFlag} -m ${cfg.mailTo}"; 24 25 levelFlag = getAttrFromPath [cfg.level] 26 { paranoid = "p"; 27 server = "s"; 28 workstation = "w"; 29 }; 30 31 cronJob = '' 32 @reboot logcheck env PATH=/run/wrappers/bin:$PATH nice -n10 ${pkgs.logcheck}/sbin/logcheck -R ${flags} 33 2 ${cfg.timeOfDay} * * * logcheck env PATH=/run/wrappers/bin:$PATH nice -n10 ${pkgs.logcheck}/sbin/logcheck ${flags} 34 ''; 35 36 writeIgnoreRule = name: {level, regex, ...}: 37 pkgs.writeTextFile 38 { inherit name; 39 destination = "/ignore.d.${level}/${name}"; 40 text = '' 41 ^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ ${regex} 42 ''; 43 }; 44 45 writeIgnoreCronRule = name: {level, user, regex, cmdline, ...}: 46 let escapeRegex = escape (stringToCharacters "\\[]{}()^$?*+|."); 47 cmdline_ = builtins.unsafeDiscardStringContext cmdline; 48 re = if regex != "" then regex else if cmdline_ == "" then ".*" else escapeRegex cmdline_; 49 in writeIgnoreRule "cron-${name}" { 50 inherit level; 51 regex = '' 52 (/usr/bin/)?cron\[[0-9]+\]: \(${user}\) CMD \(${re}\)$ 53 ''; 54 }; 55 56 levelOption = mkOption { 57 default = "server"; 58 type = types.enum [ "workstation" "server" "paranoid" ]; 59 description = lib.mdDoc '' 60 Set the logcheck level. 61 ''; 62 }; 63 64 ignoreOptions = { 65 options = { 66 level = levelOption; 67 68 regex = mkOption { 69 default = ""; 70 type = types.str; 71 description = lib.mdDoc '' 72 Regex specifying which log lines to ignore. 73 ''; 74 }; 75 }; 76 }; 77 78 ignoreCronOptions = { 79 options = { 80 user = mkOption { 81 default = "root"; 82 type = types.str; 83 description = lib.mdDoc '' 84 User that runs the cronjob. 85 ''; 86 }; 87 88 cmdline = mkOption { 89 default = ""; 90 type = types.str; 91 description = lib.mdDoc '' 92 Command line for the cron job. Will be turned into a regex for the logcheck ignore rule. 93 ''; 94 }; 95 96 timeArgs = mkOption { 97 default = null; 98 type = types.nullOr (types.str); 99 example = "02 06 * * *"; 100 description = lib.mdDoc '' 101 "min hr dom mon dow" crontab time args, to auto-create a cronjob too. 102 Leave at null to not do this and just add a logcheck ignore rule. 103 ''; 104 }; 105 }; 106 }; 107 108in 109{ 110 options = { 111 services.logcheck = { 112 enable = mkEnableOption (lib.mdDoc "logcheck cron job"); 113 114 user = mkOption { 115 default = "logcheck"; 116 type = types.str; 117 description = lib.mdDoc '' 118 Username for the logcheck user. 119 ''; 120 }; 121 122 timeOfDay = mkOption { 123 default = "*"; 124 example = "6"; 125 type = types.str; 126 description = lib.mdDoc '' 127 Time of day to run logcheck. A logcheck will be scheduled at xx:02 each day. 128 Leave default (*) to run every hour. Of course when nothing special was logged, 129 logcheck will be silent. 130 ''; 131 }; 132 133 mailTo = mkOption { 134 default = "root"; 135 example = "you@domain.com"; 136 type = types.str; 137 description = lib.mdDoc '' 138 Email address to send reports to. 139 ''; 140 }; 141 142 level = mkOption { 143 default = "server"; 144 type = types.str; 145 description = lib.mdDoc '' 146 Set the logcheck level. Either "workstation", "server", or "paranoid". 147 ''; 148 }; 149 150 config = mkOption { 151 default = "FQDN=1"; 152 type = types.lines; 153 description = lib.mdDoc '' 154 Config options that you would like in logcheck.conf. 155 ''; 156 }; 157 158 files = mkOption { 159 default = [ "/var/log/messages" ]; 160 type = types.listOf types.path; 161 example = [ "/var/log/messages" "/var/log/mail" ]; 162 description = lib.mdDoc '' 163 Which log files to check. 164 ''; 165 }; 166 167 extraRulesDirs = mkOption { 168 default = []; 169 example = [ "/etc/logcheck" ]; 170 type = types.listOf types.path; 171 description = lib.mdDoc '' 172 Directories with extra rules. 173 ''; 174 }; 175 176 ignore = mkOption { 177 default = {}; 178 description = lib.mdDoc '' 179 This option defines extra ignore rules. 180 ''; 181 type = with types; attrsOf (submodule ignoreOptions); 182 }; 183 184 ignoreCron = mkOption { 185 default = {}; 186 description = lib.mdDoc '' 187 This option defines extra ignore rules for cronjobs. 188 ''; 189 type = with types; attrsOf (submodule ignoreCronOptions); 190 }; 191 192 extraGroups = mkOption { 193 default = []; 194 type = types.listOf types.str; 195 example = [ "postdrop" "mongodb" ]; 196 description = lib.mdDoc '' 197 Extra groups for the logcheck user, for example to be able to use sendmail, 198 or to access certain log files. 199 ''; 200 }; 201 202 }; 203 }; 204 205 config = mkIf cfg.enable { 206 services.logcheck.extraRulesDirs = 207 mapAttrsToList writeIgnoreRule cfg.ignore 208 ++ mapAttrsToList writeIgnoreCronRule cfg.ignoreCron; 209 210 users.users = optionalAttrs (cfg.user == "logcheck") { 211 logcheck = { 212 group = "logcheck"; 213 isSystemUser = true; 214 shell = "/bin/sh"; 215 description = "Logcheck user account"; 216 extraGroups = cfg.extraGroups; 217 }; 218 }; 219 users.groups = optionalAttrs (cfg.user == "logcheck") { 220 logcheck = {}; 221 }; 222 223 system.activationScripts.logcheck = '' 224 mkdir -m 700 -p /var/{lib,lock}/logcheck 225 chown ${cfg.user} /var/{lib,lock}/logcheck 226 ''; 227 228 services.cron.systemCronJobs = 229 let withTime = name: {timeArgs, ...}: timeArgs != null; 230 mkCron = name: {user, cmdline, timeArgs, ...}: '' 231 ${timeArgs} ${user} ${cmdline} 232 ''; 233 in mapAttrsToList mkCron (filterAttrs withTime cfg.ignoreCron) 234 ++ [ cronJob ]; 235 }; 236}