depot/third_party/nixpkgs/nixos/modules/services/logging/logcheck.nix

281 lines
6.8 KiB
Nix

{
config,
lib,
pkgs,
...
}:
let
cfg = config.services.logcheck;
defaultRules = pkgs.runCommand "logcheck-default-rules" { preferLocalBuild = true; } ''
cp -prd ${pkgs.logcheck}/etc/logcheck $out
chmod u+w $out
rm -r $out/logcheck.*
'';
rulesDir = pkgs.symlinkJoin {
name = "logcheck-rules-dir";
paths = ([ defaultRules ] ++ cfg.extraRulesDirs);
};
configFile = pkgs.writeText "logcheck.conf" cfg.config;
logFiles = pkgs.writeText "logcheck.logfiles" cfg.files;
flags = "-r ${rulesDir} -c ${configFile} -L ${logFiles} -${levelFlag} -m ${cfg.mailTo}";
levelFlag = lib.getAttrFromPath [ cfg.level ] {
paranoid = "p";
server = "s";
workstation = "w";
};
cronJob = ''
@reboot logcheck env PATH=/run/wrappers/bin:$PATH nice -n10 ${pkgs.logcheck}/sbin/logcheck -R ${flags}
2 ${cfg.timeOfDay} * * * logcheck env PATH=/run/wrappers/bin:$PATH nice -n10 ${pkgs.logcheck}/sbin/logcheck ${flags}
'';
writeIgnoreRule =
name:
{ level, regex, ... }:
pkgs.writeTextFile {
inherit name;
destination = "/ignore.d.${level}/${name}";
text = ''
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ ${regex}
'';
};
writeIgnoreCronRule =
name:
{
level,
user,
regex,
cmdline,
...
}:
let
escapeRegex = lib.escape (lib.stringToCharacters "\\[]{}()^$?*+|.");
cmdline_ = builtins.unsafeDiscardStringContext cmdline;
re =
if regex != "" then
regex
else if cmdline_ == "" then
".*"
else
escapeRegex cmdline_;
in
writeIgnoreRule "cron-${name}" {
inherit level;
regex = ''
(/usr/bin/)?cron\[[0-9]+\]: \(${user}\) CMD \(${re}\)$
'';
};
levelOption = lib.mkOption {
default = "server";
type = lib.types.enum [
"workstation"
"server"
"paranoid"
];
description = ''
Set the logcheck level.
'';
};
ignoreOptions = {
options = {
level = levelOption;
regex = lib.mkOption {
default = "";
type = lib.types.str;
description = ''
Regex specifying which log lines to ignore.
'';
};
};
};
ignoreCronOptions = {
options = {
user = lib.mkOption {
default = "root";
type = lib.types.str;
description = ''
User that runs the cronjob.
'';
};
cmdline = lib.mkOption {
default = "";
type = lib.types.str;
description = ''
Command line for the cron job. Will be turned into a regex for the logcheck ignore rule.
'';
};
timeArgs = lib.mkOption {
default = null;
type = lib.types.nullOr (lib.types.str);
example = "02 06 * * *";
description = ''
"min hr dom mon dow" crontab time args, to auto-create a cronjob too.
Leave at null to not do this and just add a logcheck ignore rule.
'';
};
};
};
in
{
options = {
services.logcheck = {
enable = lib.mkEnableOption "logcheck cron job, to mail anomalies in the system logfiles to the administrator";
user = lib.mkOption {
default = "logcheck";
type = lib.types.str;
description = ''
Username for the logcheck user.
'';
};
timeOfDay = lib.mkOption {
default = "*";
example = "6";
type = lib.types.str;
description = ''
Time of day to run logcheck. A logcheck will be scheduled at xx:02 each day.
Leave default (*) to run every hour. Of course when nothing special was logged,
logcheck will be silent.
'';
};
mailTo = lib.mkOption {
default = "root";
example = "you@domain.com";
type = lib.types.str;
description = ''
Email address to send reports to.
'';
};
level = lib.mkOption {
default = "server";
type = lib.types.str;
description = ''
Set the logcheck level. Either "workstation", "server", or "paranoid".
'';
};
config = lib.mkOption {
default = "FQDN=1";
type = lib.types.lines;
description = ''
Config options that you would like in logcheck.conf.
'';
};
files = lib.mkOption {
default = [ "/var/log/messages" ];
type = lib.types.listOf lib.types.path;
example = [
"/var/log/messages"
"/var/log/mail"
];
description = ''
Which log files to check.
'';
};
extraRulesDirs = lib.mkOption {
default = [ ];
example = [ "/etc/logcheck" ];
type = lib.types.listOf lib.types.path;
description = ''
Directories with extra rules.
'';
};
ignore = lib.mkOption {
default = { };
description = ''
This option defines extra ignore rules.
'';
type = with lib.types; attrsOf (submodule ignoreOptions);
};
ignoreCron = lib.mkOption {
default = { };
description = ''
This option defines extra ignore rules for cronjobs.
'';
type = with lib.types; attrsOf (submodule ignoreCronOptions);
};
extraGroups = lib.mkOption {
default = [ ];
type = lib.types.listOf lib.types.str;
example = [
"postdrop"
"mongodb"
];
description = ''
Extra groups for the logcheck user, for example to be able to use sendmail,
or to access certain log files.
'';
};
};
};
config = lib.mkIf cfg.enable {
services.logcheck.extraRulesDirs =
lib.mapAttrsToList writeIgnoreRule cfg.ignore
++ lib.mapAttrsToList writeIgnoreCronRule cfg.ignoreCron;
users.users = lib.optionalAttrs (cfg.user == "logcheck") {
logcheck = {
group = "logcheck";
isSystemUser = true;
shell = "/bin/sh";
description = "Logcheck user account";
extraGroups = cfg.extraGroups;
};
};
users.groups = lib.optionalAttrs (cfg.user == "logcheck") {
logcheck = { };
};
systemd.tmpfiles.settings.logcheck = {
"/var/lib/logcheck".d = {
mode = "700";
inherit (cfg) user;
};
"/var/lock/logcheck".d = {
mode = "700";
inherit (cfg) user;
};
};
services.cron.systemCronJobs =
let
withTime = name: { timeArgs, ... }: timeArgs != null;
mkCron =
name:
{
user,
cmdline,
timeArgs,
...
}:
''
${timeArgs} ${user} ${cmdline}
'';
in
lib.mapAttrsToList mkCron (lib.filterAttrs withTime cfg.ignoreCron) ++ [ cronJob ];
};
}