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