diff --git a/nixos/modules/services/security/opensnitch.nix b/nixos/modules/services/security/opensnitch.nix index bffe17a948d1..0631d0a1863b 100644 --- a/nixos/modules/services/security/opensnitch.nix +++ b/nixos/modules/services/security/opensnitch.nix @@ -13,6 +13,7 @@ let file = pkgs.writeText "rule" (builtins.toJSON cfg); } ); + stateDir = lib.strings.match "/var/lib/([^/]+)/.+" cfg.settings.Rules.Path; in { options = { @@ -105,10 +106,9 @@ in "iptables" "nftables" ]; - default = if config.networking.nftables.enable then "nftables" else "iptables"; - defaultText = lib.literalExpression ''if config.networking.nftables.enable then "nftables" else "iptables"''; + default = "nftables"; description = '' - Which firewall backend to use. + Which firewall backend to use. `nftables` ruleset can be used for `iptables` firewall too, if `iptables` is built with nftables compatibility. ''; }; Ebpf.ModulesPath = lib.mkOption { @@ -139,7 +139,10 @@ in }; Rules.Path = lib.mkOption { - type = lib.types.path; + type = lib.types.pathWith { + inStore = false; + absolute = true; + }; default = "/var/lib/opensnitch/rules"; description = '' Path to the directory where firewall rules can be found and will @@ -158,6 +161,12 @@ in }; config = lib.mkIf cfg.enable { + assertions = [ + { + assertion = stateDir != null; + message = "`config.services.opensnitch.settings.Rules.Path` must be a sub-directory of /var/lib/, currently is ${cfg.settings.Rules.Path}"; + } + ]; security.auditd = lib.mkIf (cfg.settings.ProcMonitorMethod == "audit") { enable = true; @@ -174,8 +183,14 @@ in "" "${lib.getExe' cfg.package "opensnitchd"} --config-file ${cfg.configFile}" ]; + StateDirectory = builtins.head stateDir; # match produces a list. Null case covered by assertion. }; - preStart = lib.mkIf (cfg.rules != { }) ( + preStart = '' + # assert rules directory exists before service starts + # will be in StateDirectory due to assertion + mkdir -p ${cfg.settings.Rules.Path} + '' + + lib.optionalString (cfg.rules != { }) ( let rules = lib.flip lib.mapAttrsToList predefinedRules ( file: content: { @@ -205,13 +220,12 @@ in '' ); }; - tmpfiles.rules = [ - "d ${cfg.settings.Rules.Path} 0750 root root - -" - "L+ /etc/opensnitchd/network_aliases.json - - - - ${cfg.package}/etc/opensnitchd/network_aliases.json" - "L+ /etc/opensnitchd/system-fw.json - - - - ${cfg.package}/etc/opensnitchd/system-fw.json" - ]; }; + environment.etc."opensnitchd/network_aliases.json".source = + "${cfg.package}/etc/opensnitchd/network_aliases.json"; + environment.etc."opensnitchd/system-fw.json".source = + "${cfg.package}/etc/opensnitchd/system-fw.json"; }; meta.maintainers = with lib.maintainers; [ diff --git a/nixos/tests/opensnitch.nix b/nixos/tests/opensnitch.nix index 51560331e321..f1a152cbf607 100644 --- a/nixos/tests/opensnitch.nix +++ b/nixos/tests/opensnitch.nix @@ -1,17 +1,23 @@ { pkgs, lib, ... }: let + # opensnitch ebpf seems to handle non-x86 syscalls incorrectly + test_ebpf = pkgs.stdenv.hostPlatform.isx86; + monitorMethods = [ - "ebpf" "proc" "ftrace" "audit" - ]; + ] + ++ lib.optional test_ebpf "ebpf"; in { name = "opensnitch"; meta = with pkgs.lib.maintainers; { - maintainers = [ onny ]; + maintainers = [ + onny + grimmauld + ]; }; nodes = { @@ -94,7 +100,7 @@ in client_allowed_${m}.succeed("curl --connect-timeout 3 http://server") '') monitorMethods ) - + '' + + lib.optionalString test_ebpf '' # make sure the kernel modules were actually properly loaded client_blocked_ebpf.succeed(r"journalctl -u opensnitchd --grep '\[eBPF\] module loaded: /nix/store/.*/etc/opensnitchd/opensnitch\.o'") client_blocked_ebpf.succeed(r"journalctl -u opensnitchd --grep '\[eBPF\] module loaded: /nix/store/.*/etc/opensnitchd/opensnitch-procs\.o'")