Fork of https://framagit.org/ppom/reaction/ to implement multi-pattern match in the same filter
Go to file
ppom e56b851d15 support json, jsonnet, yaml formats
- jsonnet, json and yaml support for configuration
- json and yaml support for output formats

fix #40
fix #27
2023-10-05 12:00:00 +02:00
app support json, jsonnet, yaml formats 2023-10-05 12:00:00 +02:00
config support json, jsonnet, yaml formats 2023-10-05 12:00:00 +02:00
logo order 🧹 2023-04-26 17:11:03 +02:00
.gitignore persist flushes accross restarts. fixes #23 2023-09-09 19:32:23 +02:00
default.nix Standardize go project structure 2023-05-05 12:53:10 +02:00
go.mod support json, jsonnet, yaml formats 2023-10-05 12:00:00 +02:00
go.sum support json, jsonnet, yaml formats 2023-10-05 12:00:00 +02:00
LICENSE Add AGPL LICENSE 2023-04-11 11:03:50 +00:00
reaction.go New unified CLI design 2023-09-03 12:13:18 +02:00
README.md support json, jsonnet, yaml formats 2023-10-05 12:00:00 +02:00

reaction

a program that scans program outputs, such as logs, for repeated patterns, such as failed login attempts, and takes action, such as banning ips.

(adapted from fail2ban's presentation 😄)

🚧 this program hasn't received external audit. however, it already works well on my servers 🚧

rationale

i was using fail2ban since quite a long time, but i was a bit frustrated by its cpu consumption and all its heavy default configuration.

in my view, a security-oriented program should be simple to configure (sudo is a very bad example!) and an always-running daemon should be implemented in a fast language.

📽️ french example

configuration

this configuration file is all that should be needed to prevent brute force attacks on an ssh server.

see reaction.service and reaction.yml for the fully explained examples.

/etc/reaction.yml

definitions:
  - &iptablesban [ "iptables" "-w" "-I" "reaction" "1" "-s" "<ip>" "-j" "block" ]
  - &iptablesunban [ "iptables" "-w" "-D" "reaction" "1" "-s" "<ip>" "-j" "block" ]

patterns:
  ip: '(([0-9]{1,3}\.){3}[0-9]{1,3})|([0-9a-fA-F:]{2,90})'
  ignore:
    - '127.0.0.1'
    - '::1'

streams:
  ssh:
    cmd: [ "journalctl" "-fu" "sshd.service" ]
    filters:
      failedlogin:
        regex:
          - 'authentication failure;.*rhost=<ip>'
        retry: 3
        retryperiod: '6h'
        actions:
          ban:
            cmd: *iptablesban
          unban:
            cmd: *iptablesunban
            after: '48h'

jsonnet is also supported:

/etc/reaction.jsonnet

local iptablesban = ['iptables', '-w', '-A', 'reaction', '1', '-s', '<ip>', '-j', 'DROP'];
local iptablesunban = ['iptables', '-w', '-D', 'reaction', '1', '-s', '<ip>', '-j', 'DROP'];
{
  patterns: {
    ip: {
      regex: @'(?:(?:[0-9]{1,3}\.){3}[0-9]{1,3})|(?:[0-9a-fA-F:]{2,90})',
      ignore: ['127.0.0.1', '::1'],
    },
  },
  streams: {
    ssh: {
      cmd: ['journalctl', '-fu', 'sshd.service'],
      filters: {
        failedlogin: {
          regex: [ @'authentication failure;.*rhost=<ip>' ],
          retry: 3,
          retryperiod: '6h',
          actions: {
            ban: {
              cmd: iptablesban,
            },
            unban: {
              cmd: iptablesunban,
              after: '48h',
              onexit: true,
            },
          },
        },
      },
    },
  },
}

note that both yaml and jsonnet are extensions of json, so it is also inherently supported.

/etc/systemd/system/reaction.service

[Unit]
WantedBy=multi-user.target

[Service]
ExecStart=/path/to/reaction -c /etc/reaction.yml

ExecStartPre=/path/to/iptables -w -N reaction
ExecStartPre=/path/to/iptables -w -A reaction -j ACCEPT
ExecStartPre=/path/to/iptables -w -I reaction 1 -s 127.0.0.1 -j ACCEPT
ExecStartPre=/path/to/iptables -w -I INPUT -p all -j reaction

ExecStopPost=/path/to/iptables -w -D INPUT -p all -j reaction
ExecStopPost=/path/to/iptables -w -F reaction
ExecStopPost=/path/to/iptables -w -X reaction

StateDirectory=reaction
RuntimeDirectory=reaction
WorkingDirectory=/var/lib/reaction

database

the working directory of reaction will be used to create and read from the embedded database. if you don't know where to start it, /var/lib/reaction should be a sane choice.

socket

the socket allowing communication between the cli and server will be created at /run/reaction/reaction.socket.

compilation

you'll need the go toolchain.

$ go build .

nixos

in addition to the package and module that i didn't try to upstream to nixpkgs yet (although they are ready), i use extensively reaction on my servers. if you're using nixos, consider reading and building upon my own building blocks, my own non-root reaction conf, including conf for SSH, port scanning & Nginx common attack URLS, and the configuration for nextcloud, vaultwarden, and maddy. see also an example where it does something else than banning IPs.