Eine Reihe von Sensoren und Kameras warnt Hauswart Mike Schilli mit Kurznachrichten, sollte jemand an seiner Wohnungstür herumfummeln. Dieses Sicherheitsprinzip hat er nun auch auf die SSH-Tür seines Linux-Rechners angewandt.
Alternativ zur schon einmal in [2] vorgestellten Lösung Prowl zum Verschicken von Textnachrichten präsentiert sich in der kunterbunten Welt der Telefon-Apps ein weiterer Anbieter namens Pushover, der gegen eine Einmalzahlung von 5 US-Dollar lebenslang über ein Web-API bis zu 7500 Nachrichten im Monat an beliebig viele Smartphone- und sogar Desktop-Clients verteilt.
Holprige Browserlösung
Auf I-OS oder Android ist es die Pushover-App, in die sich der User einloggt und die dann eingehende Nachrichten als Push Notifications (Abbildung 2). anzeigt, auch wenn das Telefon per Lockscreen abgesperrt ist. Zudem bietet Pushover native Desktop-Clients für den Mac und eine etwas hanebüchene Browserlösung für den Linux-Desktop.

Abbildung 2: Das Mobiltelefon mit installierter Pushover-App zeigt einen Login-Versuch auf dem SSH-Server des überwachten Linux-Rechners an.
Dort ruft der User entweder in Chrome oder Firefox die Webseite http://client.pushover.net auf, loggt sich dort mit seinem Pushover-Account ein, erlaubt dem Browser anschließend Desktop-Notifications auf dem hauseigenen Desktop – und fertig ist der Desktop-Client. Das klappt nur, solange der Browser offen ist und ein Tab auf die Webseite von Pushover zeigt (Abbildung 3). Da dies bei mir daheim dank Pinned Tabs bereits für Gmail und Evernote der Fall ist, spielt ein Tab mehr auch keine Rolle.

Abbildung 3: Auf dem Linux-Desktop sorgt ein auf den Pushover-Service eingenordeter Browser-Tab für Popups.
Fährte aufnehmen
Den neuesten Einträgen in einer Logdatei wie »auth.log« in »/var/logs« zu folgen ist gar keine so einfache Sache. Selbst eine Unix-Funktion wie »tail -f« zu implementieren (Abbildung 1), die jeder Admin wohl mehrmals täglich nutzt, erfordert Kenntnis der Systemfunktion »seek()«, mit der ein Filehandle bis ans Ende einer Datei fahren kann.

Abbildung 1: Ein »tail -f« auf die Datei »/var/log/auth.log« zeigt erfolgreiche und fehlgeschlagene Login-Versuche am »ssh-Daemon« an.
Liefert dann ein »read()« keine Daten mehr zurück, ist dies das Ende der Datei. Kommen aber zusätzliche Zeilen zum Vorschein, hat das System diese offensichtlich zwischenzeitlich angehängt und »tail -f« gibt sie aus. Selbst wenn der Admin die Datei umbenennt, bleibt mit dem Daten konsumierenden Prozess und seinem noch offenen Filehandle alles beim Alten, das lesende Programm bekommt dergleichen gar nicht mit.
Aber selbst »tail -f« kommt aus dem Takt, falls der distributionseigene Logdatei-Rotierer einsetzt, die alte Datei wegschiebt, komprimiert und eine frische, leere an ihre Stelle setzt. In diesem Fall wäre es fatal, mit »read()« weiterhin auf dem offenen Filehandle herumzuorgeln, denn frische Daten kommen zweifellos nun in einer völlig anderen Datei an.
Dies bekommt der Log-Jäger mit, indem der in regelmäßigen Abständen prüft, ob die Datei unter dem angegebenen Namen noch immer auf den gleichen »i-node« im Dateisystem horcht. Zeigt »stat()«, dass letzterer sich geändert hat, muss der Log-Analysator das offene Filehandle schließen und ein neues auf die geänderte Datei (mit dem gleichen ursprünglichen Namen) öffnen.
Vorgefertigt
Zum Glück muss heutzutage niemand mehr diese Logik als Programm aufschreiben, denn mehrere Open-Source-Implementierungen erledigen den Job bereits perfekt. Für Python existiert zum Beispiel »Pygtail«[3], angeblich ein Python-Port des weit verbreiteten Utilty »logcheck«. Wer kein eigenes Python-Programm schreiben möchte und auf dynamische Wartbarkeit verzichten kann, darf für den ersten Teil der Alarm-Pipeline zum Parsen der System-Logdatei natürlich auch »logcheck« direkt verwenden.
Listing 1 importiert das mittels »pip3 install pygtail« installierte Modul für Python 3.x und schustert in Zeile 9 einen Pfad für die von Pygtail benötigte Merker-Datei im Verzeichnis »data« im Homedirectory des Users zusammen, im vorliegenden Fall »data/authwatch.auth.log.offset«. Hier legt Pygtail den Offset in der Datei ab, beim nächsten Aufruf liest es dahinter weiter. Falls dort neue Daten vorliegen, wird es sie auch ausgeben oder ansonsten stillschweigen.
Listing 1
authwatch
01 #!/usr/bin/python3
02 import sys
03 import os
04 import re
05 from pygtail import Pygtail
06
07 log_file = '/var/log/auth.log'
08
09 offset_file = os.path.join(os.getenv("HOME"),"data",
10 os.path.basename(sys.argv[0]) + "." +
11 os.path.basename(log_file) +
12 ".offset" )
13
14 for line in Pygtail(log_file, offset_file=offset_file):
15 if not re.search('CRON',line) and \
16 not re.search('Connection closed',line):
17 sys.stdout.write(line)
Da Cron das Skript später im Fünf-Minuten-Takt aufruft und es sich nach getaner Arbeit sofort verabschiedet, braucht es diesen persistenten Merker. Das Verzeichnis »~/data« muss der Admin vor Benutzung des Skripts einmal manuell anlegen, falls es noch nicht existiert.
Weiter blendet Listing 1 regulär auftretende Events auf, etwa Einträge, in denen Schlüsselwörter wie »CRON« oder »Connection closed« auftauchen. Die Zeilen 15 und 16 suchen danach mittels regulärer Ausdrücke und des dafür importierten Standardmoduls »re«.
Wer ein Linux mit dem viel gescholtenen »systemd« fährt, findet dort keine Logdatei »auth.log«, sondern darf mittels »journalctl« auf der Kommandozeile oder den Python-Bindings von »systemd« und deren Methode »journal« die letzten Einträge des Systemlogs herauswringen.
Statt eines Offsets in einer Datei merkt sich das Skript dann den Zeitstempel der letzten Abfrage in einer extra Datei und springt bei der nächsten mit »seek_realtime()« knapp darüber hinaus, um keine Duplikate zu erfassen. Um rotierte Logdateien braucht sich das Skript in diesem Fall keine Gedanken zu machen, da »systemd« solche Implementierungsniederungen abstrahiert.
Bequeme Web-Requests
Der zweite Teil der Alarm-Pipeline steht in Listing 2, der dort abgesetzte REST-Request auf den Pushover-API-Server verlangt zwei Tokens, die der User mit seiner Registrierung auf dem Pushover-Service erhält. Die ersten vier Wochen sind kostenlos, wer Gefallen daran findet, erwirbt für 5 Dollar eine Lizenz.
Listing 2
pushover
01 #!/usr/bin/python3
02 import requests
03 import sys
04 import re
05
06 string = sys.stdin.read()[:1024]
07
08 if re.search('\S', string):
09 r = requests.post(
10 'https://api.pushover.net/1/messages.json',
11 data = {
12 'token':'XXXXXXXXXXXXXXX',
13 'user':'YYYYYYYYYYYYYYY',
14 'message':string
15 })
Den ersten Token unter dem Schlüssel »user« sehen registrierte User auf der Dashboard-Übersicht in Abbildung 4. Der zweite Token unter dem Schlüssel »token« identifiziert die App (Abbildung 5) gegenüber Pushover, im vorliegenden Fall das Python-Skript in Listing 2, das ich bei Pushover unter dem Namen »Snapshot« registriert habe.
Für einen erfolgreichen REST-Request mit der Python-Library »requests« fehlt nur noch der Parameter »message« mit dem Nachrichtentext – und schon setzt sich die Methode »post()« in Zeile 9 mit Pushover in Verbindung. Nach Python-Manier wirft die Bibliothek bei auftretenden Fehlern Exceptions, die ohne Bearbeitung das Programm abbrechen und einen Stacktrace ausgeben, der hoffentlich bei der Behebung hilft.
Die Python-Library »requests« verspricht mit ihrem Werbeslogan “HTTP for Humans” nicht zu viel. Sie kommt jedenfalls durchdachter daher als die von mir bereits gebührend gescholtenen »urllib« und »urllib2«.
Zeile 6 in Listing 2 holt den vom ersten Teil der Pipeline gesendeten Text aus der Standardeingabe und stutzt ihn mit der in Python üblichen Syntax für Array-Slices »[:1024]« auf die bei Pushover maximal zulässige Nachrichtenlänge von 1024 Zeichen. Das »if«-Konstrukt ab Zeile 8 prüft dann mit dem regulären Ausdruck »\S«, ob die Nachricht druckbare Zeichen enthält, und beendet Leerfahrten ohne weiteres Federlesen.
Freund Cron
Bleibt nur noch, einen Cronjob aufzusetzen, der die Pipeline etwa alle fünf Minuten aufruft und der in der Environment-Variablen »$HOME« das Home- Verzeichnis des Admin findet und damit das beschreibbare Verzeichnis »data« zur Ablage der Merker-Datei:
*/5 * * * * /path/authwatch | /path/pushover
Abgesetzte Nachrichten verbreitet der Pushover-Service auf alle vom User registrierten Devices, und so kann es sein, dass ein fehlgeschlagener Login-Versuch ein ganzes Feuerwerk an Notifications auslöst, wenn in einem Raum mehrere Mobilgeräte aktiv angeschlossen sind. Aber zumindest zählt dies in den Nutzungsbeschränkungen als nur eine Nachricht, von denen pro Monat 7500 erlaubt sind, bevor der Pushover-Server den Zähler zurücksetzt. (uba)
Online PLUS
Im Screencast demonstriert Michael Schilli das Beispiel: https://www.linux-magazin.de/Ausgaben/2017/05/plus
Infos
- Listings zu diesem Artikel: https://www.linux-magazin.de/static/listings/magazin/2017/05/snapshot/
- Michael Schilli, “Private Rezeption”: Linux-Magazin 04/16, S. 94, https://www.linux-magazin.de/Ausgaben/2016/04/Perl-Snapshot
- “pygtail, Logcheck’s logtail2 for Python”: https://github.com/bgreenlee/pygtail








