Because in its default enabled state it it causes a global performance hit on all system calls (https://fedorahosted.org/fesco/ticket/1311) and unwanted spam in dmesg, in particular when using Chromium (https://github.com/NixOS/nixpkgs/issues/13710).
		
			
				
	
	
		
			120 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			Nix
		
	
	
	
	
	
			
		
		
	
	
			120 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			Nix
		
	
	
	
	
	
{ 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.stdenv.shell} -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.stdenv.shell} -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.stdenv.shell} -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";
 | 
						|
 | 
						|
      path = [ pkgs.audit ];
 | 
						|
 | 
						|
      serviceConfig = {
 | 
						|
        Type = "oneshot";
 | 
						|
        RemainAfterExit = true;
 | 
						|
        ExecStart = "@${if enabled then startScript else disableScript} audit-start";
 | 
						|
        ExecStop  = "@${stopScript} audit-stop";
 | 
						|
      };
 | 
						|
    };
 | 
						|
  };
 | 
						|
}
 |