Loading nixos/modules/security/audit.nix +29 −47 Original line number Diff line number Diff line Loading @@ -6,7 +6,6 @@ }: let cfg = config.security.audit; enabled = cfg.enable == "lock" || cfg.enable; failureModes = { silent = 0; Loading @@ -14,43 +13,14 @@ let 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)" ${lib.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}} \ # The order of the fixed rules is determined by augenrules(8) rules = pkgs.writeTextDir "audit.rules" '' -D -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 ${lib.concatLines cfg.rules} -e ${if cfg.enable == "lock" then "2" else "1"} ''; in { Loading Loading @@ -110,23 +80,35 @@ in }; }; config = { systemd.services.audit = { description = "Kernel Auditing"; wantedBy = [ "basic.target" ]; config = lib.mkIf (cfg.enable == "lock" || cfg.enable) { systemd.services.audit-rules = { description = "Load Audit Rules"; wantedBy = [ "sysinit.target" ]; before = [ "sysinit.target" "shutdown.target" ]; conflicts = [ "shutdown.target" ]; unitConfig = { DefaultDependencies = false; ConditionVirtualization = "!container"; ConditionSecurity = [ "audit" ]; ConditionKernelCommandLine = [ "!audit=0" "!audit=off" ]; }; path = [ pkgs.audit ]; serviceConfig = { Type = "oneshot"; RemainAfterExit = true; ExecStart = "@${if enabled then startScript else disableScript} audit-start"; ExecStop = "@${stopScript} audit-stop"; ExecStart = "${lib.getExe' pkgs.audit "auditctl"} -R ${rules}/audit.rules"; ExecStopPost = [ # Disable auditing "${lib.getExe' pkgs.audit "auditctl"} -e 0" # Delete all rules "${lib.getExe' pkgs.audit "auditctl"} -D" ]; }; }; }; Loading nixos/modules/security/auditd.nix +18 −7 Original line number Diff line number Diff line Loading @@ -9,12 +9,13 @@ options.security.auditd.enable = lib.mkEnableOption "the Linux Audit daemon"; config = lib.mkIf config.security.auditd.enable { boot.kernelParams = [ "audit=1" ]; # Starting auditd should also enable loading the audit rules.. security.audit.enable = lib.mkDefault true; environment.systemPackages = [ pkgs.audit ]; systemd.services.auditd = { description = "Linux Audit daemon"; description = "Security Audit Logging Service"; documentation = [ "man:auditd(8)" ]; wantedBy = [ "sysinit.target" ]; after = [ Loading @@ -28,16 +29,26 @@ conflicts = [ "shutdown.target" ]; unitConfig = { ConditionVirtualization = "!container"; ConditionSecurity = [ "audit" ]; DefaultDependencies = false; RefuseManualStop = true; ConditionVirtualization = "!container"; ConditionKernelCommandLine = [ "!audit=0" "!audit=off" ]; }; path = [ pkgs.audit ]; serviceConfig = { ExecStartPre = "${pkgs.coreutils}/bin/mkdir -p /var/log/audit"; LogsDirectory = "audit"; ExecStart = "${pkgs.audit}/bin/auditd -l -n -s nochange"; Restart = "on-failure"; # Do not restart for intentional exits. See EXIT CODES section in auditd(8). RestartPreventExitStatus = "2 4 6"; # Upstream hardening settings MemoryDenyWriteExecute = true; LockPersonality = true; RestrictRealtime = true; }; }; }; Loading nixos/tests/all-tests.nix +1 −0 Original line number Diff line number Diff line Loading @@ -226,6 +226,7 @@ in atticd = runTest ./atticd.nix; atuin = runTest ./atuin.nix; ax25 = runTest ./ax25.nix; audit = runTest ./audit.nix; audiobookshelf = runTest ./audiobookshelf.nix; auth-mysql = runTest ./auth-mysql.nix; authelia = runTest ./authelia.nix; Loading nixos/tests/audit.nix 0 → 100644 +37 −0 Original line number Diff line number Diff line { name = "audit"; nodes = { machine = { lib, pkgs, ... }: { security.audit = { enable = true; rules = [ "-a always,exit -F exe=${lib.getExe pkgs.hello} -k nixos-test" ]; }; security.auditd.enable = true; environment.systemPackages = [ pkgs.hello ]; }; }; testScript = '' machine.wait_for_unit("audit-rules.service") machine.wait_for_unit("auditd.service") with subtest("Audit subsystem gets enabled"): assert "enabled 1" in machine.succeed("auditctl -s") with subtest("Custom rule produces audit traces"): machine.succeed("hello") print(machine.succeed("ausearch -k nixos-test -sc exit_group")) with subtest("Stopping audit-rules.service disables the audit subsystem"): machine.succeed("systemctl stop audit-rules.service") assert "enabled 0" in machine.succeed("auditctl -s") ''; } pkgs/by-name/au/audit/package.nix +2 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ enablePython ? stdenv.hostPlatform == stdenv.buildPlatform, nix-update-script, testers, nixosTests, }: stdenv.mkDerivation (finalAttrs: { pname = "audit"; Loading Loading @@ -90,6 +91,7 @@ stdenv.mkDerivation (finalAttrs: { tests = { musl = pkgsCross.musl64.audit; pkg-config = testers.testMetaPkgConfig finalAttrs.finalPackage; audit = nixosTests.audit; }; }; Loading Loading
nixos/modules/security/audit.nix +29 −47 Original line number Diff line number Diff line Loading @@ -6,7 +6,6 @@ }: let cfg = config.security.audit; enabled = cfg.enable == "lock" || cfg.enable; failureModes = { silent = 0; Loading @@ -14,43 +13,14 @@ let 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)" ${lib.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}} \ # The order of the fixed rules is determined by augenrules(8) rules = pkgs.writeTextDir "audit.rules" '' -D -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 ${lib.concatLines cfg.rules} -e ${if cfg.enable == "lock" then "2" else "1"} ''; in { Loading Loading @@ -110,23 +80,35 @@ in }; }; config = { systemd.services.audit = { description = "Kernel Auditing"; wantedBy = [ "basic.target" ]; config = lib.mkIf (cfg.enable == "lock" || cfg.enable) { systemd.services.audit-rules = { description = "Load Audit Rules"; wantedBy = [ "sysinit.target" ]; before = [ "sysinit.target" "shutdown.target" ]; conflicts = [ "shutdown.target" ]; unitConfig = { DefaultDependencies = false; ConditionVirtualization = "!container"; ConditionSecurity = [ "audit" ]; ConditionKernelCommandLine = [ "!audit=0" "!audit=off" ]; }; path = [ pkgs.audit ]; serviceConfig = { Type = "oneshot"; RemainAfterExit = true; ExecStart = "@${if enabled then startScript else disableScript} audit-start"; ExecStop = "@${stopScript} audit-stop"; ExecStart = "${lib.getExe' pkgs.audit "auditctl"} -R ${rules}/audit.rules"; ExecStopPost = [ # Disable auditing "${lib.getExe' pkgs.audit "auditctl"} -e 0" # Delete all rules "${lib.getExe' pkgs.audit "auditctl"} -D" ]; }; }; }; Loading
nixos/modules/security/auditd.nix +18 −7 Original line number Diff line number Diff line Loading @@ -9,12 +9,13 @@ options.security.auditd.enable = lib.mkEnableOption "the Linux Audit daemon"; config = lib.mkIf config.security.auditd.enable { boot.kernelParams = [ "audit=1" ]; # Starting auditd should also enable loading the audit rules.. security.audit.enable = lib.mkDefault true; environment.systemPackages = [ pkgs.audit ]; systemd.services.auditd = { description = "Linux Audit daemon"; description = "Security Audit Logging Service"; documentation = [ "man:auditd(8)" ]; wantedBy = [ "sysinit.target" ]; after = [ Loading @@ -28,16 +29,26 @@ conflicts = [ "shutdown.target" ]; unitConfig = { ConditionVirtualization = "!container"; ConditionSecurity = [ "audit" ]; DefaultDependencies = false; RefuseManualStop = true; ConditionVirtualization = "!container"; ConditionKernelCommandLine = [ "!audit=0" "!audit=off" ]; }; path = [ pkgs.audit ]; serviceConfig = { ExecStartPre = "${pkgs.coreutils}/bin/mkdir -p /var/log/audit"; LogsDirectory = "audit"; ExecStart = "${pkgs.audit}/bin/auditd -l -n -s nochange"; Restart = "on-failure"; # Do not restart for intentional exits. See EXIT CODES section in auditd(8). RestartPreventExitStatus = "2 4 6"; # Upstream hardening settings MemoryDenyWriteExecute = true; LockPersonality = true; RestrictRealtime = true; }; }; }; Loading
nixos/tests/all-tests.nix +1 −0 Original line number Diff line number Diff line Loading @@ -226,6 +226,7 @@ in atticd = runTest ./atticd.nix; atuin = runTest ./atuin.nix; ax25 = runTest ./ax25.nix; audit = runTest ./audit.nix; audiobookshelf = runTest ./audiobookshelf.nix; auth-mysql = runTest ./auth-mysql.nix; authelia = runTest ./authelia.nix; Loading
nixos/tests/audit.nix 0 → 100644 +37 −0 Original line number Diff line number Diff line { name = "audit"; nodes = { machine = { lib, pkgs, ... }: { security.audit = { enable = true; rules = [ "-a always,exit -F exe=${lib.getExe pkgs.hello} -k nixos-test" ]; }; security.auditd.enable = true; environment.systemPackages = [ pkgs.hello ]; }; }; testScript = '' machine.wait_for_unit("audit-rules.service") machine.wait_for_unit("auditd.service") with subtest("Audit subsystem gets enabled"): assert "enabled 1" in machine.succeed("auditctl -s") with subtest("Custom rule produces audit traces"): machine.succeed("hello") print(machine.succeed("ausearch -k nixos-test -sc exit_group")) with subtest("Stopping audit-rules.service disables the audit subsystem"): machine.succeed("systemctl stop audit-rules.service") assert "enabled 0" in machine.succeed("auditctl -s") ''; }
pkgs/by-name/au/audit/package.nix +2 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ enablePython ? stdenv.hostPlatform == stdenv.buildPlatform, nix-update-script, testers, nixosTests, }: stdenv.mkDerivation (finalAttrs: { pname = "audit"; Loading Loading @@ -90,6 +91,7 @@ stdenv.mkDerivation (finalAttrs: { tests = { musl = pkgsCross.musl64.audit; pkg-config = testers.testMetaPkgConfig finalAttrs.finalPackage; audit = nixosTests.audit; }; }; Loading