1{ lib, pkgs, ... }:
2{
3 name = "suricata";
4 meta.maintainers = with lib.maintainers; [ felbinger ];
5
6 nodes = {
7 ids = {
8 networking.interfaces.eth1 = {
9 useDHCP = false;
10 ipv4.addresses = [
11 {
12 address = "192.168.1.2";
13 prefixLength = 24;
14 }
15 ];
16 };
17
18 # disable suricata-update because this requires an Internet connection
19 systemd.services.suricata-update.enable = false;
20
21 # install suricata package to make suricatasc program available
22 environment.systemPackages = with pkgs; [ suricata ];
23
24 services.suricata = {
25 enable = true;
26 settings = {
27 vars.address-groups.HOME_NET = "192.168.1.0/24";
28 unix-command.enabled = true;
29 outputs = [ { fast.enabled = true; } ];
30 af-packet = [ { interface = "eth1"; } ];
31 classification-file = "${pkgs.suricata}/etc/suricata/classification.config";
32 };
33 };
34
35 # create suricata.rules with the rule to detect the output of the id command
36 systemd.tmpfiles.rules = [
37 ''f /var/lib/suricata/rules/suricata.rules 644 suricata suricata 0 alert ip any any -> any any (msg:"GPL ATTACK_RESPONSE id check returned root"; content:"uid=0|28|root|29|"; classtype:bad-unknown; sid:2100498; rev:7; metadata:created_at 2010_09_23, updated_at 2019_07_26;)''
38 ];
39 };
40 helper = {
41 imports = [ ../modules/profiles/minimal.nix ];
42
43 networking.interfaces.eth1 = {
44 useDHCP = false;
45 ipv4.addresses = [
46 {
47 address = "192.168.1.1";
48 prefixLength = 24;
49 }
50 ];
51 };
52
53 services.nginx = {
54 enable = true;
55 virtualHosts."localhost".locations = {
56 "/id/".return = "200 'uid=0(root) gid=0(root) groups=0(root)'";
57 };
58 };
59 networking.firewall.allowedTCPPorts = [ 80 ];
60 };
61 };
62
63 testScript = ''
64 start_all()
65
66 # check that configuration has been applied correctly with suricatasc
67 with subtest("suricata configuration test"):
68 ids.wait_for_unit("suricata.service")
69 assert '1' in ids.succeed("suricatasc -c 'iface-list' | ${pkgs.jq}/bin/jq .message.count")
70
71 # test detection of events based on a static ruleset (output of id command)
72 with subtest("suricata rule test"):
73 helper.wait_for_unit("nginx.service")
74 ids.wait_for_unit("suricata.service")
75
76 ids.succeed("curl http://192.168.1.1/id/")
77 assert "id check returned root [**] [Classification: Potentially Bad Traffic]" in ids.succeed("tail -n 1 /var/log/suricata/fast.log"), "Suricata didn't detect the output of id comment"
78 '';
79}