Reference
Configuration
reaction can be configured using the following formats:
See FAQ "What is JSONnet and why should I use it over YAML" for a rationale.
It can be configured with either:
- one configuration file,
- or a directory containing multiple configuration files:
- files are loaded and merged in alphanumeric order,
- files beginning with
.
or_
are ignored, - files not ending with a supported extension are ignored,
- no recursion in subdirectories.
Here's a graph of reaction's model. Each concept is explained below, along with all its configuration options.
Stream
A Stream is an ASCII or UTF-8 text stream, typically logs.
It has a name and a cmd
that reaction will execute to fetch the text stream.
cmd
is an array of strings. The first string is the command, and the subsequent strings are the arguments.See FAQ "Why start, stop, stream and action commands are arrays" for an explanation.
We can attach one or more Filters to it.
{
streams: {
ssh: {
cmd: ['journalctl', '-f', '-n0', ...],
filters: {
...
},
},
nginx: {
cmd: ['tail', '-F', '-n0', ...],
filters: {
...
},
},
},
}
streams:
ssh:
cmd: ['journalctl', '-f', '-n0', ...]
filters:
...
nginx:
cmd: ['tail', '-F', '-n0', ...]
filters:
...
See Streams for details on how to write correct Stream commands for reaction.
Pattern
A pattern is essentially a regex.
It's included in Filters' regex to capture a specific part of the line, for example an IP or a username.
It's referenced in a Filter and Action by its name enclosed in <
and >
.
regex
The pattern regex.
{
patterns: {
name: {
regex: '[A-Z][a-z]*',
},
},
}
patterns:
name:
regex: '[A-Z][a-z]*'
ignore
A list of values to ignore.
{
patterns: {
name: {
regex: '[A-Z][a-z]*',
ignore: [
'Alice',
'Bob',
],
},
},
}
patterns:
name:
regex: '[A-Z][a-z]*'
ignore:
- 'Alice'
- 'Bob'
ignoreregex
A list of regex to ignore.
regex must match the full Match.
{
patterns: {
name: {
regex: '[A-Z][a-z]*',
ignoreregex: [
# Ignore names starting with Chr
'Chr.*',
],
},
},
}
patterns:
name:
regex: '[A-Z][a-z]*'
ignoreregex:
# Ignore names starting with Chr
- 'Chr.*'
type
Since v2.2.0, reaction ships with 3 special pattern types. Those types ship with a regex provided by reaction:
ip
, that matches both IPv4 and IPv6,ipv4
, that matches IPv4,ipv6
, that matches IPv6.
The default implicit type is regex
, for non-IP regexes.
{
patterns: {
ip: {
type: 'ip',
},
},
}
patterns:
ip:
type: 'ip'
{
patterns: {
ip4: {
type: 'ipv4',
},
},
}
patterns:
ip4:
type: 'ipv4'
ignorecidr
Only for patterns of an IP type.
A list of IP networks to ignore, with CIDR notation.
{
patterns: {
ip: {
type: 'ip',
ignorecidr: [
'192.168.1.0/24',
'2001:db8:2345:3456::/64',
],
},
},
}
patterns:
ip:
type: 'ip'
ignorecidr:
- '192.168.1.0/24'
- '2001:db8:2345:3456::/64'
ipv4mask
and ipv6mask
Only for patterns of an IP type.
Group IP Matches by network.
IPv6 are very cheap: malicious actors typically have 2^64 IPv6, with a /64 network mask. This is common even on residential IPs.
{
patterns: {
ip: {
type: 'ip',
ipv6mask: 64,
},
},
}
patterns:
ip:
type: 'ip'
ipv6mask: 64
With this configuration, those IPv6s will be grouped:
2001:db8:2345:3456::1
2001:db8:2345:3456::2
2001:db8:2345:3456::3
And the corresponding action will be run with the network mask:
2001:db8:2345:3456::/64
This is also possible for IPv4. Be careful doing this! Some actors may have only 1, 2, 4 IPs from a range, so this may be a bad idea.
{
patterns: {
ip: {
type: 'ip',
ipv4mask: 30, // 24 ...
ipv6mask: 64,
},
},
}
patterns:
ip:
type: 'ip'
ipv4mask: 30 # 24 ...
ipv6mask: 64
ipv4mask
only makes sense with patterns of typeip
andipv4
.ipv6mask
only makes sense with patterns of typeip
andipv6
.
Match
A match is one concrete instance of a Pattern found in the logs.
For example, if we have a pattern user
with regex [a-z]+
, and a filter with regex ^hello <user>$
, the line hello charlie
will result in the Match charlie
.
A match can be reused in Actions.
So an action with the command ['echo', '<user>']
would run echo charlie
for the previous match.
Filter
Filters run Actions when they Match regexes on a Stream.
Filters are reaction's main component, enclosing most of its runtime logic.
A Filter is attached to a Stream and receive its text stream as an input.
It applies one or more regexes to each line. When there is one or more Match in a given period, the Filter is Triggered and execute one or more Actions.
regex
A list of regexes to try matching on the input Stream.
Whenever one of them matches, a Match is created.
streams:
nginx:
...
filters:
unauthorized:
regex:
- 'HTTP/\d\.\d" 401'
streams: {
nginx: {
...
filters: {
unauthorized: {
regex: [
'HTTP/\d\.\d" 401',
],
},
},
},
}
Patterns can be referenced in the regexes. The Match will then contain the actual value matched by the Pattern and can be reused in Actions.
patterns:
ip:
type: 'ip'
streams:
nginx:
...
filters:
unauthorized:
regex:
- ' HTTP/\d\.\d" 401'
patterns: {
ip: {
type: 'ip',
},
},
streams: {
nginx: {
...
filters: {
unauthorized: {
regex: [
'^<ip> .* HTTP/\d\.\d" 401',
],
},
},
},
}
retry
How many Matches must happen before the Filter Triggers its Actions.
If not specified, defaults to 1. If specified, must be > 1.
Must be specified along with retryperiod
.
retryperiod
The retain period for Matches.
Must be specified along with retry
.
duplicate
TODO
Trigger
TODO
Action
TODO cmd ipv4only / ipv6only
Top-level options
start
/ stop
state_directory
TODO
state_directory: /var/lib/reaction
{
state_directory: /var/lib/reaction
}
concurrency
Integer that limits the maximum number of parallel actions.
- If set to a positive number, this will be the maximum number of parallel actions.
- If not specified or set to 0, it defaults to the number of CPUs on the system.
- If set to a negative number, there will be no limit on the number of parallel actions.
concurrency: 8
{
concurrency: 8
}