Events

Overview

Events are specific schemas that represent the construct of a logged event. Event generation is very dynamic and flexible, allowing for nearly any logged event to be easily generated once a SaloEventModel has been created. Once a SaloEventModel is created, logged events can easily be customized via a recipe or, for more advanced use cases, by leveraging Stencils. SALO comes with several Events out of the box, with more being developed and shared regularly.

SaloEventModel leverages pydantic for modeling to ensure strict data validation and type checking. If creating a new SaloEventModel, it is recommended to have a minimal understanding of pydantic, though being an expert is not a requirement.

Model Fields

In order to ensure SaloEventModel classes can pass along their values to other SaloEventModel and SaloStencilModel objects, SALO heavily relies on pydantic Field aliases. For example, Zeek represents the source ip address as id.orig_h, while suricata represents it as src_ip. To accomodate the multitude of variations across log schemas, pydantic Field aliases are used to define common Field names across models.

Example

Events must be a subclass of the SaloEventModel class. Let’s explore a simple example of a SaloEventModel.

In this example, we will create a SaloEventModel that produces a simple log output. Our example log event will be in JSON:

{"source": "test", "src_ip": "1.1.1.1"}

Let’s build our example event model in salo/events/example.py:

from pydantic import Field, IPvAnyAddress

from salo import SaloEventModel

class ExampleModel(SaloEventModel):
    source: str = Field(default="test")
    src_ip: IPvAnyAddress = Field(default="1.1.1.1")

    def generate(self, by_alias: bool = True, exclude_none: bool = True):
        return self.json(by_alias=by_alias, exclude_none=exclude_none)

Note

The generate method must exist. In this case, we are returning a JSON result. However, any output can be returned to include raw text or XML. In some cases, it may be more useful to generate results using a templating language, such as Jinja2.

Now, we can simply create a new recipe in example.yaml:

sessions:
  - event: salo.events.example.ExampleModel

Once the recipe is executed, salogen.py -r example.yaml, you should see the exact log output we set out to create:

{"source": "test", "src_ip": "1.1.1.1"}

API

class salo.events.SaloEventModel[source]
class Config[source]
allow_population_by_field_name = True
allow_reuse = True
static schema_extra(schema: Dict[str, Any], model) None[source]
underscore_attrs_are_private = True
validate_assignment = True