Browse Source

action_log: log to systemd, aka. enable recidive detection

master
Y 3 years ago
committed by Yves G
parent
commit
0140a934c2
8 changed files with 89 additions and 22 deletions
  1. +1
    -1
      README.md
  2. +1
    -1
      doc/install.md
  3. +1
    -1
      doc/intro_tech.md
  4. +32
    -3
      doc/logandban.md
  5. +22
    -0
      pyruse/actions/action_log.py
  6. +15
    -15
      pyruse/log.py
  7. +15
    -0
      tests/action_log.py
  8. +2
    -1
      tests/main.py

+ 1
- 1
README.md View File

@ -27,4 +27,4 @@ For more in-depth documentation, please refer to these pages:
- [the `action_noop` module](doc/noop.md)
- [the `action_email` module](doc/action_email.md)
- [the `action_dailyReport` module](doc/action_dailyReport.md)
- [the `action_nftBan` module](doc/action_nftBan.md)
- [the `action_nftBan` and `action_log` modules](doc/logandban.md)

+ 1
- 1
doc/install.md View File

@ -3,7 +3,7 @@
The software requirements are:
* a modern systemd-based Linux operating system (eg. [Archlinux](https://archlinux.org/)- or [Fedora](https://getfedora.org/)-based distributions);
* python, at least version 3.1 (or [more, depending on the modules](doc/intro_tech.md) being used);
* python, at least version 3.4 (or [more, depending on the modules](intro_tech.md) being used);
* [python-systemd](https://www.freedesktop.org/software/systemd/python-systemd/journal.html);
* [nftables](http://wiki.nftables.org/) _if_ IP address bans are to be managed;
* a sendmail-like program _if_ emails are wanted.


+ 1
- 1
doc/intro_tech.md View File

@ -15,7 +15,7 @@ It should be noted, that modern Python API are used. Thus:
* Python version ≥ 3.1 is required for managing modules (`importlib`);
* Python version ≥ 3.1 is required for loading the configuration (json’s `object_pairs_hook`);
* Python version ≥ 3.2 is required for the daily report and emails (string’s `format_map`);
* Python version ≥ 3.4 is required for the daily report (`enum`);
* Python version ≥ 3.4 is required for the daily report and logging, thus also the log action (`enum`);
* Python version ≥ 3.5 is required for IP address bans and emails, thus also the daily report (subprocess’ `run`);
* Python version ≥ 3.6 is required for emails, thus also the daily report (`headerregistry`, `EmailMessage`).


doc/action_nftBan.md → doc/logandban.md View File

@ -1,4 +1,33 @@
# Ban IP addresses after they misbehaved
# Log entries creation, and ban of IP addresses
## Log entries
The main purpose of creating new log entries, is to detect recidives in bad behaviour: after an IP address misbehaves, it gets banned, and we generate a log line for that; such log lines get counted, and eventually trigger a harsher, recidive, ban of the same IP address. Several levels of bans can thus be stacked, up to an unlimited ban, if such is wanted.
Action `action_log` takes a mandatory `message` argument, which is a template for the message to be sent.
Optionally, the log level can be changed from the default (which is “INFO”) by setting the `level` parameter; valid values are “EMERG”, “ALERT”, “CRIT”, “ERR”, “WARNING”, “NOTICE”, “INFO”, and “DEBUG” (see [Syslog severity levels](https://en.wikipedia.org/wiki/Syslog#Severity_level) for the definitions).
The `message` parameter is a Python [string format](https://docs.python.org/3/library/string.html#formatstrings).
This means that any key in the current entry may be referrenced by its name between curly braces.
This also means that literal curly braces must be doubled, lest they are read as the start of a template placeholder.
Here are some examples:
```json
{
"action": "action_log", "args": { "message": "Ban from SSH for {thatIP}." }
}
{
"action": "action_log",
"args": {
"level": "NOTICE",
"message": "Recidive ban from SSH for {thatIP}."
}
}
```
## Ban IP addresses after they misbehaved
Linux provides a number of firewall solutions: [iptables](http://www.netfilter.org/), its successor [nftables](http://wiki.nftables.org/), and many iptables frontends like [Shorewall](http://www.shorewall.net/) or RedHat’s [firewalld](http://www.firewalld.org/).
For Pyruse, **nftables** was chosen, because it is modern and light-weight, and provides interesting features.
@ -59,7 +88,7 @@ Here are examples:
}
```
## List the currently banned addresses
### List the currently banned addresses
To see what IP addresses are currently banned, here is the `nft` command:
@ -85,7 +114,7 @@ table ip Inet4 {
_Note_: The un-rounded timeouts are post-reboot restored bans.
## Un-ban an IP address
### Un-ban an IP address
It is bound to happen some day: you will want to un-ban a banned IP address.

+ 22
- 0
pyruse/actions/action_log.py View File

@ -0,0 +1,22 @@
# pyruse is intended as a replacement to both fail2ban and epylog
# Copyright © 2017–2018 Y. Gablin
# Full licensing information in the LICENSE file, or gnu.org/licences/gpl-3.0.txt if the file is missing.
import string
from pyruse import base, log
class Action(base.Action):
def __init__(self, args):
super().__init__()
self.level = log.Level[args.get("level", log.Level.INFO.name)]
self.template = args["message"]
values = {}
for (_void, name, _void, _void) in string.Formatter().parse(self.template):
if name:
values[name] = None
self.values = values
def act(self, entry):
for (name, _void) in self.values.items():
self.values[name] = entry.get(name, None)
msg = self.template.format_map(self.values)
log.log(self.level, msg)

+ 15
- 15
pyruse/log.py View File

@ -1,28 +1,28 @@
# pyruse is intended as a replacement to both fail2ban and epylog
# Copyright © 2017–2018 Y. Gablin
# Full licensing information in the LICENSE file, or gnu.org/licences/gpl-3.0.txt if the file is missing.
from enum import Enum, unique
from systemd import journal
EMERG = 0 # System is unusable.
ALERT = 1 # Action must be taken immediately.
CRIT = 2 # Critical conditions, such as hard device errors.
ERR = 3 # Error conditions.
WARNING = 4 # Warning conditions.
NOTICE = 5 # Normal but significant conditions.
INFO = 6 # Informational messages.
DEBUG = 7
@unique
class Level(Enum):
EMERG = 0 # System is unusable.
ALERT = 1 # Action must be taken immediately.
CRIT = 2 # Critical conditions, such as hard device errors.
ERR = 3 # Error conditions.
WARNING = 4 # Warning conditions.
NOTICE = 5 # Normal but significant conditions.
INFO = 6 # Informational messages.
DEBUG = 7
def log(level, string):
journal.send(string, PRIORITY = level)
journal.send(string, PRIORITY = level.value)
def debug(string):
global DEBUG
log(DEBUG, string)
log(Level.DEBUG, string)
def notice(string):
global NOTICE
log(NOTICE, string)
log(Level.NOTICE, string)
def error(string):
global ERR
log(ERR, string)
log(Level.ERR, string)

+ 15
- 0
tests/action_log.py View File

@ -0,0 +1,15 @@
# pyruse is intended as a replacement to both fail2ban and epylog
# Copyright © 2017–2018 Y. Gablin
# Full licensing information in the LICENSE file, or gnu.org/licences/gpl-3.0.txt if the file is missing.
from unittest.mock import patch
from pyruse import log
from pyruse.actions.action_log import Action
@patch('pyruse.actions.action_log.log.log')
def whenLogThenRightSystemdCall(mockLog):
for level in log.Level:
Action({"level": level.name, "message": "Test: {text}"}).act({"text": "test message"})
mockLog.assert_called_with(level, "Test: test message")
def unitTests():
whenLogThenRightSystemdCall()

+ 2
- 1
tests/main.py View File

@ -20,7 +20,7 @@ def main():
# Unit tests
import filter_equals, filter_greaterOrEquals, filter_in, filter_inNetworks, filter_lowerOrEquals, filter_pcre, filter_pcreAny, filter_userExists
import action_counterRaise, action_counterReset, action_dailyReport, action_email, action_nftBan
import action_counterRaise, action_counterReset, action_dailyReport, action_email, action_log, action_nftBan
filter_equals.unitTests()
filter_greaterOrEquals.unitTests()
@ -34,6 +34,7 @@ def main():
action_counterReset.unitTests()
action_dailyReport.unitTests()
action_email.unitTests()
action_log.unitTests()
action_nftBan.unitTests()
# Integration test


Loading…
Cancel
Save