aboutsummaryrefslogtreecommitdiff
path: root/nixpkgs/nixos/modules/security/audit.nix
diff options
context:
space:
mode:
Diffstat (limited to 'nixpkgs/nixos/modules/security/audit.nix')
-rw-r--r--nixpkgs/nixos/modules/security/audit.nix123
1 files changed, 123 insertions, 0 deletions
diff --git a/nixpkgs/nixos/modules/security/audit.nix b/nixpkgs/nixos/modules/security/audit.nix
new file mode 100644
index 00000000000..2b22bdd9f0a
--- /dev/null
+++ b/nixpkgs/nixos/modules/security/audit.nix
@@ -0,0 +1,123 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+ cfg = config.security.audit;
+ enabled = cfg.enable == "lock" || cfg.enable;
+
+ failureModes = {
+ silent = 0;
+ printk = 1;
+ panic = 2;
+ };
+
+ disableScript = pkgs.writeScript "audit-disable" ''
+ #!${pkgs.runtimeShell} -eu
+ # Explicitly disable everything, as otherwise journald might start it.
+ auditctl -D
+ auditctl -e 0 -a task,never
+ '';
+
+ # TODO: it seems like people like their rules to be somewhat secret, yet they will not be if
+ # put in the store like this. At the same time, it doesn't feel like a huge deal and working
+ # around that is a pain so I'm leaving it like this for now.
+ startScript = pkgs.writeScript "audit-start" ''
+ #!${pkgs.runtimeShell} -eu
+ # Clear out any rules we may start with
+ auditctl -D
+
+ # Put the rules in a temporary file owned and only readable by root
+ rulesfile="$(mktemp)"
+ ${concatMapStrings (x: "echo '${x}' >> $rulesfile\n") cfg.rules}
+
+ # Apply the requested rules
+ auditctl -R "$rulesfile"
+
+ # Enable and configure auditing
+ auditctl \
+ -e ${if cfg.enable == "lock" then "2" else "1"} \
+ -b ${toString cfg.backlogLimit} \
+ -f ${toString failureModes.${cfg.failureMode}} \
+ -r ${toString cfg.rateLimit}
+ '';
+
+ stopScript = pkgs.writeScript "audit-stop" ''
+ #!${pkgs.runtimeShell} -eu
+ # Clear the rules
+ auditctl -D
+
+ # Disable auditing
+ auditctl -e 0
+ '';
+in {
+ options = {
+ security.audit = {
+ enable = mkOption {
+ type = types.enum [ false true "lock" ];
+ default = false;
+ description = ''
+ Whether to enable the Linux audit system. The special `lock' value can be used to
+ enable auditing and prevent disabling it until a restart. Be careful about locking
+ this, as it will prevent you from changing your audit configuration until you
+ restart. If possible, test your configuration using build-vm beforehand.
+ '';
+ };
+
+ failureMode = mkOption {
+ type = types.enum [ "silent" "printk" "panic" ];
+ default = "printk";
+ description = "How to handle critical errors in the auditing system";
+ };
+
+ backlogLimit = mkOption {
+ type = types.int;
+ default = 64; # Apparently the kernel default
+ description = ''
+ The maximum number of outstanding audit buffers allowed; exceeding this is
+ considered a failure and handled in a manner specified by failureMode.
+ '';
+ };
+
+ rateLimit = mkOption {
+ type = types.int;
+ default = 0;
+ description = ''
+ The maximum messages per second permitted before triggering a failure as
+ specified by failureMode. Setting it to zero disables the limit.
+ '';
+ };
+
+ rules = mkOption {
+ type = types.listOf types.str; # (types.either types.str (types.submodule rule));
+ default = [];
+ example = [ "-a exit,always -F arch=b64 -S execve" ];
+ description = ''
+ The ordered audit rules, with each string appearing as one line of the audit.rules file.
+ '';
+ };
+ };
+ };
+
+ config = {
+ systemd.services.audit = {
+ description = "Kernel Auditing";
+ wantedBy = [ "basic.target" ];
+
+ unitConfig = {
+ ConditionVirtualization = "!container";
+ ConditionSecurity = [ "audit" ];
+ };
+
+
+ path = [ pkgs.audit ];
+
+ serviceConfig = {
+ Type = "oneshot";
+ RemainAfterExit = true;
+ ExecStart = "@${if enabled then startScript else disableScript} audit-start";
+ ExecStop = "@${stopScript} audit-stop";
+ };
+ };
+ };
+}