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