elos – Event Logging and Management

Author: Wolfgang Gehrhardt, Systems Engineer at emlix GmbH

Inhomogene Log-Formate unter Linux

Das Feld an Log-Formaten unter Linux ist so breit wie inhomogen: Die unterschiedlichen textbasierten Log-Formate sind im Allgemeinen nicht darauf fokussiert maschinenlesbar zu sein sondern sollen schnell und unkompliziert mit Board-Mitteln ausgelesen werden können.

Syslog als Informationsquelle

Das Syslog ist in den meisten Fällen im journalctl abgebildet oder in /var/log/messages zu finden. Während jounrnalctl sein eigenes Tooling zum auslesen mitbringt, sind für das klassische Syslog (rfc5424- www.rfc-editor.org/rfc/rfc5424) Kommandos wie cat /var/log&/messages, tail -f /var/log/messages oder beliebig fortgeschrittene grep- Statements sind eine gute Möglichkeit, um an die gewünschten Informationen zu gelangen.

Mit den gleichen Tools lassen sich auch weiteren Informationsquellen wie dem Kernel-Log oder den umfangreichen Kernel-Schnittstellen im procfs und sysfs einiges an Informationen entlocken. Für das procfs und sysfs ist in aller Regel ein genaueres Studium der Manpages vorauszusetzen.

Zwar sind der Inhalt und das Format gängiger Vertreter wie /proc/cpuinfo, /proc/mem oder einzelner Dateien aus der /proc/<pid>-Kategorie bekannt. Den Großteil jedoch schauen viele Entwickler sich eher selten an und die durch Leerzeichen getrennten Zahlenkolonnen einiger procfs-Schnittstellen sind auch oft ein Quell der Freude beim Parsen.

Weitere Quellen

Neben diesen Quellen gibt es noch weitere Schnittstellen die Entwickler zur Informationsbeschaffung heranziehen können. Diese Kategorie könnte als binär oder maschinenlesbar klassifiziert werden. So zum Beispiel ist das Netlink-Interface des Kernels ein häufig unterschätzter Kandidat, um wichtige Informationen des Systems zu erhalten.

Daneben bekommen Berkly-Packet-Filter immer mehr Beachtung und versprechen in Zukunft spannende Einblicke in das laufende System.

Neben all diesen sehr systemnahen Schnittstellen gibt es nahezu endlos weitere Schnittstellen im User-Space. Hier kann jedes Programm ganz nach der Philosophie “everything is a file” seine eigene Schnittstelle in Form von Sockets, Pipes, Dateien oder Shared-memory bereitstellen. Die Vielfalt an Mechanismen ist groß und wird durch die eingesetzten Formate noch komplizierter. Middleware und Standards wie DBus können dem nur begrenzt entgegenwirken.

 

Unbefriedigend und ein generisches Problem

Es zeigt sich also, dass es aufwändig und unbefriedigend ist, Linux-Logs wichtige Systeminformationen zu entlocken. Zudem ist es ein generisches Problem, das viele Entwickler aus ihrer Arbeit kennen werden.

Die definierte und kontrollierte Reaktion auf bestimmte Events in Fehler- oder auch in Normalfällen ist für Embedded Systeme aber obligatorisch. Daher suchten emlix Entwickler im Rahmen eines Kundenprojektes mit Elektrobit nach einer guten Lösung innerhalb der Open Source Community. Doch leider Fehlanzeige – Das Team fand keine Lösung, die den Ansprüchen genügte.

 

Eine Lösung musste her

Also war es naheliegend für die Emlix Entwickler, selbst eine passende Lösung zu entwickeln, die dann auch der Open Source Community zur Verfügung gestellt werden sollte. Zentrale Anforderungen waren es, ein System automatisiert zu überwachen und auf spezifische Ereignisse angemessen zu reagieren.

Dabei stellte sich die nicht zu unterschätzende Aufgabe alle oben erwähnten Quellen

  • Zu evaluieren

  • Deren Output zu interpretieren

  • Für die eigenen Aufgabenstellung aufzubereiten

  • Den Ursprung eines Ereignisses zu validieren

  • Und abschließend auf das Ereignis zu reagieren.

Weiterhin sollten die auftretenden Events persistent gespeichert werden und die angezapften Schnittstellen sollten gut zu pflegen und zu warten sein. Mit diesen Anforderungen wurde das Projekt elos aus der Traufe gehoben.

elos

elos (Event Logging and Management System) bringt nach einem Jahr Open Source mittlerweile folgende Funktionen mit sich:

  • Normalisieren: Standardisierung von System-Events für ein maschinenlesbares und möglichst einfach auszuwertendes Format

  • Sammeln: Ein wartbares Konzept zur Erhebung und Publikation von Events

  • Offene IPC Architektur: Erweiterbar durch eine Client-API über beliebige IPC-Schnittstellen

  • Security-Bewertung: Welche Events dürfen aus welcher Quelle kommen?

  • Persistenz: Adaptives Speicher-Konzept, Was wird Wie und Wo gespeichert?

Normalisieren

Die Grundidee ist es, möglichst trivial und eindeutig die Bedeutung eines Events bestimmen zu können: Beispielsweise kann ein EEACCESS-Fehler eines open-Systemcalls, gedeutet werden als Datei existiert nicht oder Datei ist nicht zugreifbar. Hierbei ist nicht eindeutig, ob dieser Fehler ein klassischer Error ist oder eher ein Resultat des Versuches eine Konfigurationsdatei an verschiedenen Stellen im System zu finden.

Ein klassischer Syslog eintrag könnte so aussehen:

<38>Jan 1 00:00:04 myapp[98]: Failed to open file

In <38> ist die Information codiert, dass es sich um eine Nachricht mit dem Schwere-Grad Info und der Kategorie (Syslog-Sprachgebrauch “Facility”) Security handelt.

Weiterhin wird durch myapp[98] sichtbar, welcher Prozess der Ursprung war und dessen Prozess ID. Das eigentliche Ereignis ist Kodiert als “Failed to open File”. Diese Information muss jetzt geparsed und verstanden werden, was unverhältnismäßig aufwendig werden kann.

elos Event Formate

Mit dem elos Event Format soll vermieden werden immer wieder erneut Texte interpretieren zu müssen. Weiterhin soll die Interpretation und Evaluation von Ereignissen für Maschinen so effizient wie möglich gestaltet werden.

Die einfachste Möglichkeit ist der Vergleich einer Zahl oder eines Symbols. Angelehnt an das gut funktionierende System von HTTP-Response-Codes bietet es sich an auch Events mit Integer-Codes zu benennen. Idealerweise wird der Fehler aus unserem Beispiel so zu einem “4004” übersetzt “FILE_NOT_FOUND”. Über weitere Attribute kann dieser zentralen Aussage noch mehr Bedeutung verliehen bzw. näher spezifiziert werden. Dafür stellt das elos-Event Format die folgenden Attribute bereit:

  • Date: Timestamp, Zeitpunkt des Events
  • MessageCode: Ein einfacher numerischer Identifier für einen Event (z.B. o.g. 4004)
  • Classification: 64 bit Feld zur Klassifizierung, Annotation von Events
  • Severity: Zur Gruppierung nach Schwere bzw. Dringlichkeit des Events
  • HardwareID: Eindeutig System-Kennung um es einem System zuzuordnen
  • Source: Der Ursprung Auslöser des Events, üblicherweise des Prozesses selbst
  • Payload: Zusätzliche Informationen für das Event

 

Date

Dabei sind alle Attribute optional, bis auf das Date Feld. Da ein Event ohne zeitliche Einordnung schwer zu betrachten ist oder in der Regel keine Relevanz hat setzt elos im Falle des Fehlens den Zeitpunkt des Eintreffens im elos-System.

Classification

Über das Classification Bit-Feld können Events mehreren Kategorien zugeordnet werden. Diese Klassifizierung der Events erlaubt Fragestellungen um das Geschehen vor nach und während eines Ereignisses zu analysieren. So lassen sich alle sicherheitsrelevanten Events mit Bezug zur Hardware im Netzwerk-Kontext über einen Event-Filter beschreiben.

Payload und Message-Code

Das Payload-Feld erlaubt einem Event zusätzliche Informationen zu geben, wobei der Message-Code eines Events den Inhalt und das Format bestimmt.

Entlastung anderer Programme

In Summe sind diese 7 Attribute der kleinste gemeinsame Nenner um Ereignisse in einen einheitlichen, vergleichbaren Kontext zu bringen. Diese Normalisierung sorgt dafür, dass die Aufwände für die Interpretation von Ereignisse möglichst gering sind. Ganz nach der Philosophie “Erledige eine Aufgabe und die aber richtig” können Anwendungen sich so auf ihre eigentliche Aufgabe konzentrieren. Die Beschaffung und Interpretation der nötigen Informationen erledigt elos für das Programm.

Sammeln - Event-Scanner

elos verwendet sogenannte Scanner-Plugins um unterschiedliche Event-Quellen in einem System zu überwachen. Der Scanner-Plugin Ansatz bietet eine flexible Möglichkeit die verschiedenen Quellen für Informationen zentral in elos-Events zu überführen.

Dabei sind Scanner als Plugins realisiert und werden über die elosd-Konfiguration aktiviert und konfiguriert. Wie auch für andere Plugin-Typen (Client- und Storage-Plugins) abstrahiert ein Scanner-Plugin die Art und Weise wie eine Event-Resource auszulesen und zu interpretieren ist.

Event-Resourcen für Scanner können vielfältig sein und reichen von unix-sockets wie /dev/log (syslog-scanner) über Character-Devices wie /dev/kmsg bis zu Netlink Endpoints wie AUDIT.

Über die elos-Plugin-API ist es ebenfalls möglich eigene Scanner zu implementieren. Diese können Entwickler ausserhalb der elos-Quellen und damit unabhängig vom elos-Kern und anderen Komponenten bauen und warten.

Basis Scanner

Als Basis-Plugins bringt elos aktuell Scanner für folgende Quellen zur Überwachung mit:

  • Das Syslog

  • Den Linux-Kernel-Ringbuffer

  • Den Out-Of-Memory-Killer

... 
    "Scanner": { 
        "Plugins": { 
            "OomKiller": { 
                "File": "scanner_oomkiller.so", 
                "Run": "always" 
            }, 
            "SyslogScanner": { 
                "File": "scanner_syslog.so", 
                "Run": "always", 
                "Config": { 
                    "SyslogPath": "/dev/log", 
                    "MappingRules": { 
                        "MessageCodes": { 
                            "8004": ".event.source.appName 'sshd' STRCMP .e.payload r'authentication failure' REGEX AND", 
                            "8005": ".event.source.appName 'sshd' STRCMP .e.payload r'Accepted password for' REGEX AND", 
                            "1001": "1 1 EQ" 
                        } 
                    } 
                } 
            }, 
            "KmsgScanner": { 
                "File": "scanner_kmsg.so", 
                "Run": "always", 
                "Config": { 
                    "KmsgFile": "/dev/kmsg" 
                } 
            } 
        } 
    } 
... 

Offene IPC Architektur: Bereitstellen einer Client-API über beliebige IPC-Schnittstellen

elos verfolgt im Kern den Ansatz eventgetriebener Architekturen. Um eine möglichst einfache Integration von unterschiedlichen Kombinationen von IPC Lösungen in einem System zu unterstützen, kommt auch hier ein Plugin-System zum Einsatz. Dieses erlaubt je nach Systemkonfiguration die benötigten IPC-Mechanismen zu verwenden. Dabei dient elos als klassischer Message-Broker und der Austausch von Events erfolgt nach dem Publish-/Subscriber Prinzip. So sind als Client-Plugins Schnittstellen von Shared-Memory und Unix-Domain Sockets bis hin zu zusätzlicher Middleware wie DBus, Ubus, MQTT, OPCUA realisierbar.
 

Unabhängig von der jeweiligen IPC-Anbindung hat ein Client prinzipiell die folgende Interaktionsmöglichkeiten:

  • Publishen von Events
  • Subscriben auf Events
  • Fetchen von kürzlich vergangenen Events

Je nach Implementierung des Client-Plugins müssen nicht alle Funktionen bereitgestellt werden.

elos stellt in seiner Basis-Konfiguration ein TCP-Client-Plugin als IPC-Mechanismus bereit. Schon mit diesem Plugin lassen sich komplexere Szenarien konfigurieren wie zum Beispiel Lokale und Public Interfaces.

... 
    "LocalTcpClient": { 
        "File": "client_tcp.so", 
        "Run": "always", 
        "Config": { 
            "Port": 54321, 
            "Interface": "127.0.0.1", 
            ... 
        } 
    }, 
... 
    "PublicTcpClient": { 
        "File": "client_tcp.so", 
        "Run": "always", 
        "Config": { 
            "Port": 54322, 
            "Interface": "192.168.192.4", 
            ... 
        } 
    }, 
... 

Für die einfache Entwicklung bietet elos mit libelos und libelos-cpp eine C und CPP API an, die die Kommunikation mit elos abstrahiert. Weitere Language-Bindings wie etwa Python, go, Rust sind im entstehen und dank des simpel gehaltenen elos-Protokolls in modernen Sprachen schnell implementiert.

 

Securitybewertung – Event-Authorisation und Blacklisting

Das Erheben und Propagieren von Events in einem System, auf die unterschiedliche Teilnehmer reagieren wirft den Aspekt des Auditierens von Events auf. Es muss verhindert werden, dass mutwillig oder irrtümlich Events publiziert werden die kritische Prozesse steuern oder in Gang setzen können. Deshalb muss sichergestellt sein, dass bestimmte Events nur aus autorisierten Quellen akzeptiert werden. In elos ist dies über eine Kombination aus Event-Blacklisting und Event-Autorisation gelöst.

 

Event-Blacklisting

In elos erlaubt die Konfiguration eine sogenannte Blacklist für Events. Diese erfolgt jeweils pro konfiguriertem “Client-Input” in Form eines Event-Filters. Wird ein Event von der Blacklist erkannt bzw. trifft der Event-Filter zu, muss der sendende Prozess zum erfolgreichen publizieren des Events von elos autorisiert werden. Ist dies nicht der Fall wird an seiner statt ein Security-Event 8007 (UNAUTHORIZED_PUBLISHING) publiziert und so auch protokolliert.

... 
    "LocalTcpClient": { 
        "File": "client_tcp.so", 
        "Run": "always", 
        "Config": { 
            "Port": 54321, 
            "Interface": "127.0.0.1", 
            ... 
            "EventBlacklist": ".event.messageCode 1000 LE", 
            ... 
        } 
    }, 
... 
    "PublicTcpClient": { 
        "File": "client_tcp.so", 
        "Run": "always", 
        "Config": { 
            "Port": 54322, 
            "Interface": "0.0.0.0", 
            "EventBlacklist": "1 1 EQ", 
            ... 
        } 
    }, 
... 

Event-Autorisation

Prozesse die als autorisiert gelten, dürfen auf der Blacklist geführte Events publizieren. Autorisierte Prozesse werden analog zur Event-Blacklist pro Client-Input definiert. Im Unterschied kann eine Liste an Prozess-Filtern definiert werden und ein Prozess muss einem Filter genügen um als autorisiert zu gelten.

  • Definition von Prozess-Filter, hier am Beispiel für einer public und private TCP-Client-Plugin Instanz

... 
    "LocalTcpClient": { 
        "File": "client_tcp.so", 
        "Run": "always", 
        "Config": { 
            "Port": 54321, 
            "Interface": "127.0.0.1", 
            ... 
            "authorizedProcesses": [ 
                ".process.uid 0 EQ .process.gid 0 EQ AND .process.exec '/usr/bin/elosc' STRCMP AND", 
                ".process.gid 200 EQ .process.exec '/usr/bin/elosc' STRCMP AND", 
                ".process.pid 1 EQ" 
            ] 
            ... 
        } 
    }, 
... 
    "PublicTcpClient": { 
        "File": "client_tcp.so", 
        "Run": "always", 
        "Config": { 
            "Port": 54322, 
            "Interface": "0.0.0.0", 
            ... 
            "authorizedProcesses": [], 
            ... 
        } 
    }, 
... 

Persistenz: Adaptives Speicher System

Sind die Events erfasst, normalisiert und autorisiert, steht die Aufgabe der Persistenz an. Einfach alle Events ihrem auftreten nach wegzuschreiben bedeutet eine hohe Systemlast, ein hohes Datenvolumen und damit einhergehend ein hohe Beanspruchung an die zugrundeliegenden Speichermedien. Die Aufgabe der Persistenz hat emlix unter folgenden Aspekten betrachtet:

  • Was soll oder darf explizit nicht gespeichert werden
  • Wie kann möglichst schonend für die Hardware, insbesondere für Flash-Speicher gespeichert werden
  • Wie können Events optimal für die später Auswertung gespeichert werden

Unter Berücksichtigung dieser Aspekte hat emlix für eine optimale Speicherung eine Klassifizierung eingeführt:

  • Wie häufig treten Events auf?

  • Wie sensibel ist die Information?

  • Wie lange muss sie verfügbar sein?

 

Damit können unterschiedliche Klassen zur Speicherung abgeleitet werden.

So zum Beispiel sollten sensible Informationen auf einer Verschlüsselten Partition abgelegt werden. Häufige Events wie System-Temperatur oder System-Last eher in einem flüchtigen tmpfs oder in einer dafür optimierten Timeseries Database. Während Events zu Hardware-Fehlern eher in einem rotierenden log-Datei auf einer herkömmlichen Partition gut aufgehoben sind.

Um der unterschiedlichen Natur solcher Speicher-Klassen gerecht zu werden, hat emlix sich für ein Modulares System entschieden und über sogenannte Storage-Plugins realisiert. Dabei definiert ein Storage-Plugin die Art und Weise der Speicherung von Events (Plain-Text, Binär-Format, Datenbank). Während über die Konfiguration der Instanz eines Plugins die zu speichernden Events und auch das Speichermedium definiert wird.

Die Erweiterung über Plugins erlaubt hier zukunftssicher neue Storage-Technologien anzubinden ohne den elos-Kern ändern zu müssen.

elos stellt von Haus aus ein JSON-, sqlite- und DLT-Plugin (Diagnostic Log and Trace) bereit und kann über die elos-Plugin-API zudem einfach um eigene spezialisierte Storage-Plugins in C/C++ ergänzt werden.

Dazu im folgenden die Beispiel-Konfiguration eines json-logfiles für Coredumps und eines für alle anderen Events der mit der Severity Warning oder höher.

... 
    "syslog": { 
        "File": "backend_json.so", 
        "Run": "always", 
        "Filter": [ 
            ".e.severity 3 LE .e.severity 0 GT AND" 
        ], 
        "Config": { 
            "StoragePath": "/var/log/syslog_%host%_%date%_%count%.log", 
        } 
    }, 
    "coredump": { 
        "File": "backend_json.so", 
        "Run": "always", 
        "Filter": [ 
            ".e.messageCode 5005 EQ" 
        ], 
        "Config": { 
            "StoragePath": "/mnt/coredumps/coredumps_%host%_%date%_%count%.log", 
        } 
    }, 
... 

Dieses adaptive Konzept erlaubt dem Systemintegrator je nach Situation und Anwendungsfall flexibel den Strom von Events in geeignete Speicherformate und -orte zu dirigieren.

 

Ein Jahr Open Source – elos geht weiter

Seit einem Jahr ist elos unter der MIT Lizenz als Open Source Projekt auf github zu finden. Neben dem elos-Kern-Repository hat sich ein kleines Ökosystem gebildet:

 

Künftig hat emlix sich zum Ziel gesetzt

  • Das Feld der Scanner zu erweitern für

    • Hardware Monitoring

    • Prozess und System Monitoring

    • Netzwerk Monitoring

  • Erweiterter IPC – Support

    • Unix-Domain Socket

    • Nach bedarf Standard-Schnittstellen wie z.B. OPCUA-default Device Profile

  • Erweiterung und Verbesserung des Elos-Entwicklungs und Plugin Ökosystems

  • Verbesserung der Integration mit systemd/journald

Auch als vergleichsweise junges Projekt, bietet elos schon heute Ansätze und Konzepte, die Linux Systeme effizienter gestalten können – Nicht nur im embedded Bereich, sondern auch für Desktop Anwendungen oder Server Systeme.

Weitere Informationen

Wenn Sie mehr über elos und die Einsatzmöglichkeiten wissen wollen, freuen wir uns auf Ihre Kontaktaufnahme.

 

Ihre Ansprechpartner

Das elos Team
Phone +49 551 304460
solutions@~@emlix.com