3214367796
iptables backend is currently broken for unknown reasons. `nftables` backend works for iptables firewall too, if built with nftablesCompat = true (our default).
236 lines
7.9 KiB
Nix
236 lines
7.9 KiB
Nix
{
|
|
config,
|
|
lib,
|
|
pkgs,
|
|
...
|
|
}:
|
|
let
|
|
cfg = config.services.opensnitch;
|
|
format = pkgs.formats.json { };
|
|
|
|
predefinedRules = lib.flip lib.mapAttrs cfg.rules (
|
|
name: cfg: {
|
|
file = pkgs.writeText "rule" (builtins.toJSON cfg);
|
|
}
|
|
);
|
|
stateDir = lib.strings.match "/var/lib/([^/]+)/.+" cfg.settings.Rules.Path;
|
|
in
|
|
{
|
|
options = {
|
|
services.opensnitch = {
|
|
enable = lib.mkEnableOption "Opensnitch application firewall";
|
|
package = lib.mkPackageOption pkgs "opensnitch" { };
|
|
|
|
rules = lib.mkOption {
|
|
default = { };
|
|
example = lib.literalExpression ''
|
|
{
|
|
"tor" = {
|
|
"name" = "tor";
|
|
"enabled" = true;
|
|
"action" = "allow";
|
|
"duration" = "always";
|
|
"operator" = {
|
|
"type" ="simple";
|
|
"sensitive" = false;
|
|
"operand" = "process.path";
|
|
"data" = "''${lib.getBin pkgs.tor}/bin/tor";
|
|
};
|
|
};
|
|
};
|
|
'';
|
|
|
|
description = ''
|
|
Declarative configuration of firewall rules.
|
|
All rules will be stored in `/var/lib/opensnitch/rules` by default.
|
|
Rules path can be configured with `settings.Rules.Path`.
|
|
See [upstream documentation](https://github.com/evilsocket/opensnitch/wiki/Rules)
|
|
for available options.
|
|
'';
|
|
|
|
type = lib.types.submodule {
|
|
freeformType = format.type;
|
|
};
|
|
};
|
|
|
|
upstreamDefaults = lib.mkOption {
|
|
description = ''
|
|
Whether to base the config declared in {option}`services.opensnitch.settings` on the upstream example config (<https://github.com/evilsocket/opensnitch/blob/master/daemon/data/default-config.json>)
|
|
|
|
Disable this if you want to declare your opensnitch config from scratch.
|
|
'';
|
|
type = lib.types.bool;
|
|
default = true;
|
|
};
|
|
|
|
configFile = lib.mkOption {
|
|
description = ''
|
|
Path to JSON config file. See: <https://github.com/evilsocket/opensnitch/blob/master/daemon/data/default-config.json>
|
|
If this option is set, it will override any configuration done in options.services.opensnitch.settings.
|
|
'';
|
|
example = "/etc/opensnitchd/default-config.json";
|
|
type = lib.types.path;
|
|
default =
|
|
let
|
|
generatedConfig = format.generate "config.json" cfg.settings;
|
|
in
|
|
if cfg.upstreamDefaults then
|
|
pkgs.runCommand "opensnitch-config.json" { } ''
|
|
${lib.getExe pkgs.jq} -s '.[0] * .[1]' ${cfg.package}/etc/opensnitchd/default-config.json ${format.generate "config.json" cfg.settings} >"$out"
|
|
''
|
|
else
|
|
generatedConfig;
|
|
defaultText = lib.literalMD "JSON file generated from {option}`services.opensnitch.settings`";
|
|
};
|
|
|
|
settings = lib.mkOption {
|
|
type = lib.types.submodule {
|
|
freeformType = format.type;
|
|
|
|
options = {
|
|
ProcMonitorMethod = lib.mkOption {
|
|
type = lib.types.enum [
|
|
"ebpf"
|
|
"proc"
|
|
"ftrace"
|
|
"audit"
|
|
];
|
|
default = "ebpf";
|
|
description = ''
|
|
Which process monitoring method to use.
|
|
'';
|
|
};
|
|
|
|
Firewall = lib.mkOption {
|
|
type = lib.types.enum [
|
|
"iptables"
|
|
"nftables"
|
|
];
|
|
default = "nftables";
|
|
description = ''
|
|
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 {
|
|
type = lib.types.nullOr lib.types.path;
|
|
default =
|
|
if cfg.settings.ProcMonitorMethod == "ebpf" then
|
|
"${config.boot.kernelPackages.opensnitch-ebpf}/etc/opensnitchd"
|
|
else
|
|
null;
|
|
defaultText = lib.literalExpression ''
|
|
if cfg.settings.ProcMonitorMethod == "ebpf" then
|
|
"''${config.boot.kernelPackages.opensnitch-ebpf}/etc/opensnitchd"
|
|
else null;
|
|
'';
|
|
description = ''
|
|
Configure eBPF modules path. Used when
|
|
`settings.ProcMonitorMethod` is set to `ebpf`.
|
|
'';
|
|
};
|
|
|
|
Audit.AudispSocketPath = lib.mkOption {
|
|
type = lib.types.path;
|
|
default = "/run/audit/audispd_events";
|
|
description = ''
|
|
Configure audit socket path. Used when
|
|
`settings.ProcMonitorMethod` is set to `audit`.
|
|
'';
|
|
};
|
|
|
|
Rules.Path = lib.mkOption {
|
|
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
|
|
get stored by the NixOS module.
|
|
'';
|
|
};
|
|
|
|
};
|
|
};
|
|
description = ''
|
|
opensnitchd configuration. Refer to [upstream documentation](https://github.com/evilsocket/opensnitch/wiki/Configurations)
|
|
for details on supported values.
|
|
'';
|
|
};
|
|
};
|
|
};
|
|
|
|
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;
|
|
plugins.af_unix.active = true;
|
|
};
|
|
|
|
systemd = {
|
|
packages = [ cfg.package ];
|
|
services.opensnitchd = {
|
|
wantedBy = [ "multi-user.target" ];
|
|
path = lib.optionals (cfg.settings.ProcMonitorMethod == "audit") [ pkgs.audit ];
|
|
serviceConfig = {
|
|
ExecStart = [
|
|
""
|
|
"${lib.getExe' cfg.package "opensnitchd"} --config-file ${cfg.configFile}"
|
|
];
|
|
StateDirectory = builtins.head stateDir; # match produces a list. Null case covered by assertion.
|
|
};
|
|
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: {
|
|
inherit (content) file;
|
|
local = "${cfg.settings.Rules.Path}/${file}.json";
|
|
}
|
|
);
|
|
in
|
|
''
|
|
# Remove all firewall rules from rules path (configured with
|
|
# cfg.settings.Rules.Path) that are symlinks to a store-path, but aren't
|
|
# declared in `cfg.rules` (i.e. all networks that were "removed" from
|
|
# `cfg.rules`).
|
|
find ${cfg.settings.Rules.Path} -type l -lname '${builtins.storeDir}/*' ${
|
|
lib.optionalString (rules != { }) ''
|
|
-not \( ${
|
|
lib.concatMapStringsSep " -o " ({ local, ... }: "-name '${baseNameOf local}*'") rules
|
|
} \) \
|
|
''
|
|
} -delete
|
|
${lib.concatMapStrings (
|
|
{ file, local }:
|
|
''
|
|
ln -sf '${file}' "${local}"
|
|
''
|
|
) rules}
|
|
''
|
|
);
|
|
};
|
|
};
|
|
|
|
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; [
|
|
onny
|
|
grimmauld
|
|
];
|
|
}
|