at master 3.8 kB view raw
1{ 2 config, 3 lib, 4 pkgs, 5 ... 6}: 7let 8 cfg = config.security.audit; 9 10 failureModes = { 11 silent = 0; 12 printk = 1; 13 panic = 2; 14 }; 15 16 # The order of the fixed rules is determined by augenrules(8) 17 rules = pkgs.writeTextDir "audit.rules" '' 18 -D 19 -b ${toString cfg.backlogLimit} 20 -f ${toString failureModes.${cfg.failureMode}} 21 -r ${toString cfg.rateLimit} 22 ${lib.concatLines cfg.rules} 23 -e ${if cfg.enable == "lock" then "2" else "1"} 24 ''; 25in 26{ 27 options = { 28 security.audit = { 29 enable = lib.mkOption { 30 type = lib.types.enum [ 31 false 32 true 33 "lock" 34 ]; 35 default = false; 36 description = '' 37 Whether to enable the Linux audit system. The special `lock` value can be used to 38 enable auditing and prevent disabling it until a restart. Be careful about locking 39 this, as it will prevent you from changing your audit configuration until you 40 restart. If possible, test your configuration using build-vm beforehand. 41 ''; 42 }; 43 44 failureMode = lib.mkOption { 45 type = lib.types.enum [ 46 "silent" 47 "printk" 48 "panic" 49 ]; 50 default = "printk"; 51 description = "How to handle critical errors in the auditing system"; 52 }; 53 54 backlogLimit = lib.mkOption { 55 type = lib.types.int; 56 # Significantly increase from the kernel default of 64 because a 57 # normal systems generates way more logs. 58 default = 1024; 59 description = '' 60 The maximum number of outstanding audit buffers allowed; exceeding this is 61 considered a failure and handled in a manner specified by failureMode. 62 ''; 63 }; 64 65 rateLimit = lib.mkOption { 66 type = lib.types.int; 67 default = 0; 68 description = '' 69 The maximum messages per second permitted before triggering a failure as 70 specified by failureMode. Setting it to zero disables the limit. 71 ''; 72 }; 73 74 rules = lib.mkOption { 75 type = lib.types.listOf lib.types.str; # (types.either types.str (types.submodule rule)); 76 default = [ ]; 77 example = [ "-a exit,always -F arch=b64 -S execve" ]; 78 description = '' 79 The ordered audit rules, with each string appearing as one line of the audit.rules file. 80 ''; 81 }; 82 }; 83 }; 84 85 config = lib.mkIf (cfg.enable == "lock" || cfg.enable) { 86 boot.kernelParams = [ 87 # A lot of audit events happen before the systemd service starts. Thus 88 # enable it via the kernel commandline to have the audit subsystem ready 89 # as soon as the kernel starts. 90 "audit=1" 91 # Also set the backlog limit because the kernel default is too small to 92 # capture all of them before the service starts. 93 "audit_backlog_limit=${toString cfg.backlogLimit}" 94 ]; 95 96 environment.systemPackages = [ pkgs.audit ]; 97 98 systemd.services.audit-rules = { 99 description = "Load Audit Rules"; 100 wantedBy = [ "sysinit.target" ]; 101 before = [ 102 "sysinit.target" 103 "shutdown.target" 104 ]; 105 conflicts = [ "shutdown.target" ]; 106 107 unitConfig = { 108 DefaultDependencies = false; 109 ConditionVirtualization = "!container"; 110 ConditionKernelCommandLine = [ 111 "!audit=0" 112 "!audit=off" 113 ]; 114 }; 115 116 serviceConfig = { 117 Type = "oneshot"; 118 RemainAfterExit = true; 119 ExecStart = "${lib.getExe' pkgs.audit "auditctl"} -R ${rules}/audit.rules"; 120 ExecStopPost = [ 121 # Disable auditing 122 "${lib.getExe' pkgs.audit "auditctl"} -e 0" 123 # Delete all rules 124 "${lib.getExe' pkgs.audit "auditctl"} -D" 125 ]; 126 }; 127 }; 128 }; 129}