Reaction

Daemon that scans program outputs for repeated patterns, and takes action

Declared in: projects/Reaction/default.nix

Try the service in a VM

  1. Install Nix
    Bash
    $ apt install --yes curl git jq nix
    Bash
    $ apt install --yes curl git jq nix
    Bash
    $ pacman --sync --refresh --noconfirm curl git jq nix
  2. Download a configuration file
    # default.nix
    {
      ngipkgs ? import (fetchTarball "https://github.com/ngi-nix/ngipkgs/tarball/main") { },
    }:
    ngipkgs.demo-vm (
      { pkgs, ... }:
      {
        services.reaction = {
          enable = true;
          settingsFiles = [ ./example-ssh.jsonnet ];
          # Prefer `runAsRoot` to `false` in a production deployment, this is just for the demo
          runAsRoot = true;
          # and give the reaction user and service the proper permissions (see the non-root example, below).
        };
      }
    )
    
  3. Enable binary substituters
    Bash
    $ export NIX_CONFIG='substituters = https://cache.nixos.org/ https://ngi.cachix.org/
    trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= ngi.cachix.org-1:n+CAL72ROC3qQuLxIHpV+Tw5t42WhXmMhprAGkRSrOw='
  4. Build and run a virtual machine
    Bash
    $ nix-build ./default.nix && ./result
    Bash
    $ nix-build ./default.nix && ./result
    Bash
    $ rev=$(nix-instantiate --eval --attr sources.nixpkgs.rev https://github.com/ngi-nix/ngipkgs/archive/master.tar.gz | jq --raw-output)
    $ nix-shell -I nixpkgs=https://github.com/NixOS/nixpkgs/archive/$rev.tar.gz --packages nix --run "nix-build ./default.nix && ./result"
    Bash
    $ nix-build ./default.nix && ./result
  5. Usage Instructions
    1. Reaction is a very powerful rules based engine.

      A common usecase is to scan ssh and webserver logs, and to ban hosts that cause multiple authentication errors.

      Provide a configuration file for reaction, for example: example.jsonnet.

    2. Run the demo vm, it runs an ssh server at port 10022, a user nixos with password nixos exists.

      Run journalctl -f inside the demo vm.

    3. Open a new terminal in your host system and run this ssh command:

      ssh -p 10022 nixos@localhost -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null

      Attempt login to the demo vm with wrong passwords thrice.

    4. Go back to the demo vm terminal, and notice that you've been banned in the last line.

    5. To unban yourself, go to the vm terminal and run: sudo reaction flush

    6. Attempt to login with the correct password.

Options

services.reaction
services.reaction.checkConfig

Check the syntax of the configuration files at build time

Type:
boolean
Default:
true
Declared in:
nixos/modules/services/security/reaction.nix
services.reaction.enable

Whether to enable enable reaction.

Type:
boolean
Default:
false
Declared in:
nixos/modules/services/security/reaction.nix
services.reaction.loglevel

reaction's loglevel. One of DEBUG, INFO, WARN, ERROR.

Type:
null or one of "DEBUG", "INFO", "WARN", "ERROR"
Default:
null
Declared in:
nixos/modules/services/security/reaction.nix
services.reaction.package

The reaction package to use.

Type:
package
Default:
pkgs.reaction
Declared in:
nixos/modules/services/security/reaction.nix
services.reaction.runAsRoot

Whether to run reaction as root. Defaults to false, where an unprivileged reaction user is created.

Be sure to give it sufficient permissions. Example config permitting iptables and journalctl use

{
  # allows reading journal logs of processess
  users.users.reaction.extraGroups = [ "systemd-journal" ];

  # allows modifying ip firewall rules
  systemd.services.reaction.unitConfig.ConditionCapability = "CAP_NET_ADMIN";
  systemd.services.reaction.serviceConfig = {
    CapabilityBoundingSet = [ "CAP_NET_ADMIN" ];
    AmbientCapabilities = [ "CAP_NET_ADMIN" ];
  };

  # optional, if more control over ssh logs is needed
  services.openssh.settings.LogLevel = lib.mkDefault "VERBOSE";
}
Type:
boolean
Default:
false
Declared in:
nixos/modules/services/security/reaction.nix
services.reaction.settings

Configuration for reaction. See the wiki.

The settings are written as a YAML file.

Can be used in combination with settingsFiles option, both will be present in the configuration directory.

Type:
open submodule of (YAML 1.1 value)
Default:
{ }
Declared in:
nixos/modules/services/security/reaction.nix
services.reaction.settingsFiles

Configuration for reaction, see the wiki.

reaction supports JSON, YAML and JSONnet. For those who prefer to take advantage of JSONnet rather than Nix.

Can be used in combination with settings option, both will be present in the configuration directory.

Type:
list of absolute path
Default:
[ ]
Declared in:
nixos/modules/services/security/reaction.nix
services.reaction.stopForFirewall

Whether to stop reaction when reloading the firewall.

The presence of a reaction chain in the INPUT table may cause the firewall reload to fail. One can alternatively cherry-pick the right iptables commands to execute before and after the firewall

{
  systemd.services.firewall.serviceConfig = {
    ExecStopPre = [ "${pkgs.iptables}/bin/iptables -w -D INPUT -p all -j reaction" ];
    ExecStartPost = [ "${pkgs.iptables}/bin/iptables -w -I INPUT -p all -j reaction" ];
  };
}
Type:
boolean
Default:
false
Declared in:
nixos/modules/services/security/reaction.nix

Examples

non-root
{ pkgs, ... }:
{
  config = {
    services.reaction = {
      enable = true;
      stopForFirewall = true;
      # example.jsonnet/example.yml can be copied and modified from ${pkgs.reaction}/share/examples
      settingsFiles = [ "${pkgs.reaction}/share/examples/example.jsonnet" ];
      runAsRoot = false;
    };
    services.openssh.enable = true;
    # If not running as root you need to give the reaction user and service the proper permissions

    # allows reading journal logs of processess
    users.users.reaction.extraGroups = [ "systemd-journal" ];

    # allows modifying ip firewall rules
    systemd.services.reaction.unitConfig.ConditionCapability = "CAP_NET_ADMIN";
    systemd.services.reaction.serviceConfig = {
      CapabilityBoundingSet = [ "CAP_NET_ADMIN" ];
      AmbientCapabilities = [ "CAP_NET_ADMIN" ];
    };
  };
}

Declared in: projects/Reaction/services/reaction/examples/non-root.nix

root
{ pkgs, ... }:
{
  config = {
    services.reaction = {
      enable = true;
      stopForFirewall = true; # with this enabled restarting firewall will restart reaction
      settingsFiles = [
        # supports jsonnet as well as yml config formats
        "${pkgs.reaction}/share/examples/example.jsonnet"
        # "${pkgs.reaction}/share/examples/example.yml"
      ];
      runAsRoot = true;
    };
    networking.firewall.enable = true;
  };
}

Declared in: projects/Reaction/services/reaction/examples/root.nix

Metadata

This project is funded by NLnet through these subgrants:

Core
Reaction

Related links: