nixos/fastnetmon-advanced: init
This commit is contained in:
parent
924c682627
commit
bf5f01ee52
3 changed files with 225 additions and 0 deletions
|
@ -107,6 +107,8 @@
|
|||
|
||||
- [NNCP](http://www.nncpgo.org/). Added nncp-daemon and nncp-caller services. Configuration is set with [programs.nncp.settings](#opt-programs.nncp.settings) and the daemons are enabled at [services.nncp](#opt-services.nncp.caller.enable).
|
||||
|
||||
- [FastNetMon Advanced](https://fastnetmon.com/product-overview/), a commercial high performance DDoS detector / sensor. Available as [services.fastnetmon-advanced](#opt-services.fastnetmon-advanced.enable).
|
||||
|
||||
- [tuxedo-rs](https://github.com/AaronErhardt/tuxedo-rs), Rust utilities for interacting with hardware from TUXEDO Computers.
|
||||
|
||||
- [audiobookshelf](https://github.com/advplyr/audiobookshelf/), a self-hosted audiobook and podcast server. Available as [services.audiobookshelf](#opt-services.audiobookshelf.enable).
|
||||
|
|
|
@ -907,6 +907,7 @@
|
|||
./services/networking/eternal-terminal.nix
|
||||
./services/networking/expressvpn.nix
|
||||
./services/networking/fakeroute.nix
|
||||
./services/networking/fastnetmon-advanced.nix
|
||||
./services/networking/ferm.nix
|
||||
./services/networking/firefox-syncserver.nix
|
||||
./services/networking/fireqos.nix
|
||||
|
|
222
nixos/modules/services/networking/fastnetmon-advanced.nix
Normal file
222
nixos/modules/services/networking/fastnetmon-advanced.nix
Normal file
|
@ -0,0 +1,222 @@
|
|||
{ config, lib, pkgs, ... }:
|
||||
|
||||
let
|
||||
# Background information: FastNetMon requires a MongoDB to start. This is because
|
||||
# it uses MongoDB to store its configuration. That is, in a normal setup there is
|
||||
# one collection with one document.
|
||||
# To provide declarative configuration in our NixOS module, this database is
|
||||
# completely emptied and replaced on each boot by the fastnetmon-setup service
|
||||
# using the configuration backup functionality.
|
||||
|
||||
cfg = config.services.fastnetmon-advanced;
|
||||
settingsFormat = pkgs.formats.yaml { };
|
||||
|
||||
# obtain the default configs by starting up ferretdb and fcli in a derivation
|
||||
default_configs = pkgs.runCommand "default-configs" {
|
||||
nativeBuildInputs = [
|
||||
pkgs.ferretdb
|
||||
pkgs.fastnetmon-advanced # for fcli
|
||||
pkgs.proot
|
||||
];
|
||||
} ''
|
||||
mkdir ferretdb fastnetmon $out
|
||||
FERRETDB_TELEMETRY="disable" FERRETDB_HANDLER="sqlite" FERRETDB_STATE_DIR="$PWD/ferretdb" FERRETDB_SQLITE_URL="file:$PWD/ferretdb/" ferretdb &
|
||||
|
||||
cat << EOF > fastnetmon/fastnetmon.conf
|
||||
${builtins.toJSON {
|
||||
mongodb_username = "";
|
||||
}}
|
||||
EOF
|
||||
proot -b fastnetmon:/etc/fastnetmon -0 fcli create_configuration
|
||||
proot -b fastnetmon:/etc/fastnetmon -0 fcli set bgp default
|
||||
proot -b fastnetmon:/etc/fastnetmon -0 fcli export_configuration backup.tar
|
||||
tar -C $out --no-same-owner -xvf backup.tar
|
||||
'';
|
||||
|
||||
# merge the user configs into the default configs
|
||||
config_tar = pkgs.runCommand "fastnetmon-config.tar" {
|
||||
nativeBuildInputs = with pkgs; [ jq ];
|
||||
} ''
|
||||
jq -s add ${default_configs}/main.json ${pkgs.writeText "main-add.json" (builtins.toJSON cfg.settings)} > main.json
|
||||
mkdir hostgroup
|
||||
${lib.concatImapStringsSep "\n" (pos: hostgroup: ''
|
||||
jq -s add ${default_configs}/hostgroup/0.json ${pkgs.writeText "hostgroup-${toString (pos - 1)}-add.json" (builtins.toJSON hostgroup)} > hostgroup/${toString (pos - 1)}.json
|
||||
'') hostgroups}
|
||||
mkdir bgp
|
||||
${lib.concatImapStringsSep "\n" (pos: bgp: ''
|
||||
jq -s add ${default_configs}/bgp/0.json ${pkgs.writeText "bgp-${toString (pos - 1)}-add.json" (builtins.toJSON bgp)} > bgp/${toString (pos - 1)}.json
|
||||
'') bgpPeers}
|
||||
tar -cf $out main.json ${lib.concatImapStringsSep " " (pos: _: "hostgroup/${toString (pos - 1)}.json") hostgroups} ${lib.concatImapStringsSep " " (pos: _: "bgp/${toString (pos - 1)}.json") bgpPeers}
|
||||
'';
|
||||
|
||||
hostgroups = lib.mapAttrsToList (name: hostgroup: { inherit name; } // hostgroup) cfg.hostgroups;
|
||||
bgpPeers = lib.mapAttrsToList (name: bgpPeer: { inherit name; } // bgpPeer) cfg.bgpPeers;
|
||||
|
||||
in {
|
||||
options.services.fastnetmon-advanced = with lib; {
|
||||
enable = mkEnableOption "the fastnetmon-advanced DDoS Protection daemon";
|
||||
|
||||
settings = mkOption {
|
||||
description = ''
|
||||
Extra configuration options to declaratively load into FastNetMon Advanced.
|
||||
|
||||
See the [FastNetMon Advanced Configuration options reference](https://fastnetmon.com/docs-fnm-advanced/fastnetmon-advanced-configuration-options/) for more details.
|
||||
'';
|
||||
type = settingsFormat.type;
|
||||
default = {};
|
||||
example = literalExpression ''
|
||||
{
|
||||
networks_list = [ "192.0.2.0/24" ];
|
||||
gobgp = true;
|
||||
gobgp_flow_spec_announces = true;
|
||||
}
|
||||
'';
|
||||
};
|
||||
hostgroups = mkOption {
|
||||
description = "Hostgroups to declaratively load into FastNetMon Advanced";
|
||||
type = types.attrsOf settingsFormat.type;
|
||||
default = {};
|
||||
};
|
||||
bgpPeers = mkOption {
|
||||
description = "BGP Peers to declaratively load into FastNetMon Advanced";
|
||||
type = types.attrsOf settingsFormat.type;
|
||||
default = {};
|
||||
};
|
||||
|
||||
enableAdvancedTrafficPersistence = mkOption {
|
||||
description = "Store historical flow data in clickhouse";
|
||||
type = types.bool;
|
||||
default = false;
|
||||
};
|
||||
|
||||
traffic_db.settings = mkOption {
|
||||
type = settingsFormat.type;
|
||||
description = "Additional settings for /etc/fastnetmon/traffic_db.conf";
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkMerge [ (lib.mkIf cfg.enable {
|
||||
environment.systemPackages = with pkgs; [
|
||||
fastnetmon-advanced # for fcli
|
||||
];
|
||||
|
||||
environment.etc."fastnetmon/license.lic".source = "/var/lib/fastnetmon/license.lic";
|
||||
environment.etc."fastnetmon/gobgpd.conf".source = "/run/fastnetmon/gobgpd.conf";
|
||||
environment.etc."fastnetmon/fastnetmon.conf".source = pkgs.writeText "fastnetmon.conf" (builtins.toJSON {
|
||||
mongodb_username = "";
|
||||
});
|
||||
|
||||
services.ferretdb.enable = true;
|
||||
|
||||
systemd.services.fastnetmon-setup = {
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "ferretdb.service" ];
|
||||
path = with pkgs; [ fastnetmon-advanced config.systemd.package ];
|
||||
script = ''
|
||||
fcli create_configuration
|
||||
fcli delete hostgroup global
|
||||
fcli import_configuration ${config_tar}
|
||||
systemctl --no-block try-restart fastnetmon
|
||||
'';
|
||||
serviceConfig.Type = "oneshot";
|
||||
};
|
||||
|
||||
systemd.services.fastnetmon = {
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "ferretdb.service" "fastnetmon-setup.service" "polkit.service" ];
|
||||
path = with pkgs; [ iproute2 ];
|
||||
unitConfig = {
|
||||
# Disable logic which shuts service when we do too many restarts
|
||||
# We do restarts from sudo fcli commit and it's expected that we may have many restarts
|
||||
# Details: https://github.com/systemd/systemd/issues/2416
|
||||
StartLimitInterval = 0;
|
||||
};
|
||||
serviceConfig = {
|
||||
ExecStart = "${pkgs.fastnetmon-advanced}/bin/fastnetmon --log_to_console";
|
||||
|
||||
LimitNOFILE = 65535;
|
||||
# Restart service when it fails due to any reasons, we need to keep processing traffic no matter what happened
|
||||
Restart= "on-failure";
|
||||
RestartSec= "5s";
|
||||
|
||||
DynamicUser = true;
|
||||
CacheDirectory = "fastnetmon";
|
||||
RuntimeDirectory = "fastnetmon"; # for gobgpd config
|
||||
StateDirectory = "fastnetmon"; # for license file
|
||||
};
|
||||
};
|
||||
|
||||
security.polkit.enable = true;
|
||||
security.polkit.extraConfig = ''
|
||||
polkit.addRule(function(action, subject) {
|
||||
if (action.id == "org.freedesktop.systemd1.manage-units" &&
|
||||
subject.isInGroup("fastnetmon")) {
|
||||
if (action.lookup("unit") == "gobgp.service") {
|
||||
var verb = action.lookup("verb");
|
||||
if (verb == "start" || verb == "stop" || verb == "restart") {
|
||||
return polkit.Result.YES;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
'';
|
||||
|
||||
# We don't use the existing gobgp NixOS module and package, because the gobgp
|
||||
# version might not be compatible with fastnetmon. Also, the service name
|
||||
# _must_ be 'gobgp' and not 'gobgpd', so that fastnetmon can reload the config.
|
||||
systemd.services.gobgp = {
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "network.target" ];
|
||||
description = "GoBGP Routing Daemon";
|
||||
unitConfig = {
|
||||
ConditionPathExists = "/run/fastnetmon/gobgpd.conf";
|
||||
};
|
||||
serviceConfig = {
|
||||
Type = "notify";
|
||||
ExecStartPre = "${pkgs.fastnetmon-advanced}/bin/fnm-gobgpd -f /run/fastnetmon/gobgpd.conf -d";
|
||||
SupplementaryGroups = [ "fastnetmon" ];
|
||||
ExecStart = "${pkgs.fastnetmon-advanced}/bin/fnm-gobgpd -f /run/fastnetmon/gobgpd.conf --sdnotify";
|
||||
ExecReload = "${pkgs.fastnetmon-advanced}/bin/fnm-gobgpd -r";
|
||||
DynamicUser = true;
|
||||
AmbientCapabilities = "cap_net_bind_service";
|
||||
};
|
||||
};
|
||||
})
|
||||
|
||||
(lib.mkIf (cfg.enable && cfg.enableAdvancedTrafficPersistence) {
|
||||
## Advanced Traffic persistence
|
||||
## https://fastnetmon.com/docs-fnm-advanced/fastnetmon-advanced-traffic-persistency/
|
||||
|
||||
services.clickhouse.enable = true;
|
||||
|
||||
services.fastnetmon-advanced.settings.traffic_db = true;
|
||||
|
||||
services.fastnetmon-advanced.traffic_db.settings = {
|
||||
clickhouse_batch_size = lib.mkDefault 1000;
|
||||
clickhouse_batch_delay = lib.mkDefault 1;
|
||||
traffic_db_host = lib.mkDefault "127.0.0.1";
|
||||
traffic_db_port = lib.mkDefault 8100;
|
||||
clickhouse_host = lib.mkDefault "127.0.0.1";
|
||||
clickhouse_port = lib.mkDefault 9000;
|
||||
clickhouse_user = lib.mkDefault "default";
|
||||
clickhouse_password = lib.mkDefault "";
|
||||
};
|
||||
environment.etc."fastnetmon/traffic_db.conf".text = builtins.toJSON cfg.traffic_db.settings;
|
||||
|
||||
systemd.services.traffic_db = {
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "network.target" ];
|
||||
serviceConfig = {
|
||||
ExecStart = "${pkgs.fastnetmon-advanced}/bin/traffic_db";
|
||||
# Restart service when it fails due to any reasons, we need to keep processing traffic no matter what happened
|
||||
Restart= "on-failure";
|
||||
RestartSec= "5s";
|
||||
|
||||
DynamicUser = true;
|
||||
};
|
||||
};
|
||||
|
||||
}) ];
|
||||
|
||||
meta.maintainers = lib.teams.wdz.members;
|
||||
}
|
Loading…
Reference in a new issue