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.

graph of the concepts

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]*'

Regex syntax is documented here

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.*'

Regex syntax is documented here

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 type ip and ipv4.
  • ipv6mask only makes sense with patterns of type ip and ipv6.

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',
        ],
      },
    },
  },
}

Regex syntax is documented here

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
}