at 16.09-beta 3.7 kB view raw
1{ config, lib, pkgs, ... }: 2 3with lib; 4 5let 6 cfg = config.security.audit; 7 enabled = cfg.enable == "lock" || cfg.enable; 8 9 failureModes = { 10 silent = 0; 11 printk = 1; 12 panic = 2; 13 }; 14 15 disableScript = pkgs.writeScript "audit-disable" '' 16 #!${pkgs.stdenv.shell} -eu 17 # Explicitly disable everything, as otherwise journald might start it. 18 auditctl -D 19 auditctl -e 0 -a task,never 20 ''; 21 22 # TODO: it seems like people like their rules to be somewhat secret, yet they will not be if 23 # put in the store like this. At the same time, it doesn't feel like a huge deal and working 24 # around that is a pain so I'm leaving it like this for now. 25 startScript = pkgs.writeScript "audit-start" '' 26 #!${pkgs.stdenv.shell} -eu 27 # Clear out any rules we may start with 28 auditctl -D 29 30 # Put the rules in a temporary file owned and only readable by root 31 rulesfile="$(mktemp)" 32 ${concatMapStrings (x: "echo '${x}' >> $rulesfile\n") cfg.rules} 33 34 # Apply the requested rules 35 auditctl -R "$rulesfile" 36 37 # Enable and configure auditing 38 auditctl \ 39 -e ${if cfg.enable == "lock" then "2" else "1"} \ 40 -b ${toString cfg.backlogLimit} \ 41 -f ${toString failureModes.${cfg.failureMode}} \ 42 -r ${toString cfg.rateLimit} 43 ''; 44 45 stopScript = pkgs.writeScript "audit-stop" '' 46 #!${pkgs.stdenv.shell} -eu 47 # Clear the rules 48 auditctl -D 49 50 # Disable auditing 51 auditctl -e 0 52 ''; 53in { 54 options = { 55 security.audit = { 56 enable = mkOption { 57 type = types.enum [ false true "lock" ]; 58 default = false; 59 description = '' 60 Whether to enable the Linux audit system. The special `lock' value can be used to 61 enable auditing and prevent disabling it until a restart. Be careful about locking 62 this, as it will prevent you from changing your audit configuration until you 63 restart. If possible, test your configuration using build-vm beforehand. 64 ''; 65 }; 66 67 failureMode = mkOption { 68 type = types.enum [ "silent" "printk" "panic" ]; 69 default = "printk"; 70 description = "How to handle critical errors in the auditing system"; 71 }; 72 73 backlogLimit = mkOption { 74 type = types.int; 75 default = 64; # Apparently the kernel default 76 description = '' 77 The maximum number of outstanding audit buffers allowed; exceeding this is 78 considered a failure and handled in a manner specified by failureMode. 79 ''; 80 }; 81 82 rateLimit = mkOption { 83 type = types.int; 84 default = 0; 85 description = '' 86 The maximum messages per second permitted before triggering a failure as 87 specified by failureMode. Setting it to zero disables the limit. 88 ''; 89 }; 90 91 rules = mkOption { 92 type = types.listOf types.str; # (types.either types.str (types.submodule rule)); 93 default = []; 94 example = [ "-a exit,always -F arch=b64 -S execve" ]; 95 description = '' 96 The ordered audit rules, with each string appearing as one line of the audit.rules file. 97 ''; 98 }; 99 }; 100 }; 101 102 config = { 103 systemd.services.audit = { 104 description = "Kernel Auditing"; 105 wantedBy = [ "basic.target" ]; 106 107 unitConfig.ConditionVirtualization = "!container"; 108 109 path = [ pkgs.audit ]; 110 111 serviceConfig = { 112 Type = "oneshot"; 113 RemainAfterExit = true; 114 ExecStart = "@${if enabled then startScript else disableScript} audit-start"; 115 ExecStop = "@${stopScript} audit-stop"; 116 }; 117 }; 118 }; 119}