ubuntuusers.de

Verzeichnisse mit Path Units überwachen

Status: Gelöst | Ubuntu-Version: Server 18.04 (Bionic Beaver)
Antworten |

Tronde Team-Icon

Avatar von Tronde

Anmeldungsdatum:
23. November 2006

Beiträge: 1640

Hallo ubuntuusers,

schon seit einiger Zeit überwache ich ausgewählte Verzeichnisse mit Path Units. Mein Ziel ist es, mir bei Änderungen am Verzeichnisinhalt eine E-Mail mit dem aktuellen Verzeichnisinhalt zukommen zu lassen. Das gesamte Verfahren habe ich ausführlich in einem Blog-Artikel 🇩🇪 beschrieben.

Das Verfahren in Kürze

  1. Leeres Verzeichnis 'DIR' wird mit Path Unit überwacht

  2. Wird in 'DIR' eine Datei erstellt, wird eine Service-Unit aktiviert

  3. Die Service-Unit führt ein Skript aus, welches den aktuellen Verzeichnisinhalt von 'DIR' per E-Mail versendet

Wenn nun jedoch eine Datei in 'DIR' erstellt und umgehend wieder gelöscht wird, ist das Verzeichnis zum Ausführungszeitpunkt der Service-Unit bereits wieder leer. Es wird also eine E-Mail versendet, laut welcher der Verzeichnisinhalt leer ist. Auffällig ist meiner Meinung nach auch, dass ich nur eine Nachricht erhalte, obwohl zwei Änderungen stattgefunden haben (Datei anlegen/löschen).

Hat von euch jemand eine Idee, wie ich es anstelle, dass ich über beide Aktionen benachrichtigt werde und nachvollziehen kann, welche Datei zwischenzeitlich erzeugt wurde?

MfG
Tronde

seahawk1986

Anmeldungsdatum:
27. Oktober 2006

Beiträge: 11260

Wohnort: München

Das Problem dürfte sein, dass nicht mehrere Instanzen der Unit gleichzeitig aktiv sein können und die inotify-Events verloren gehen, die auftreten, während die Unit bereits aktiv ist.

Ich denke nicht, dass man das überhaupt zuverlässig mit Path-Units lösen kann, die zeitliche Auflösung ist da immer beschränkt - praktischer dürfte z.B. ein Python-Skript sein, das z.B. mit python3-pyinotify auf die Events reagiert und alle 10 Sekunden (den Wert in Zeile 27 kann man je nach Bedarf anpassen) Mails mit den gesammelten Meldungen verschickt, falls welche vorliegen. Hier mal ein Ansatz mit asyncio (weil ich gerade dabei bin mehr darüber zu lernen):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#!/usr/bin/env python3
import asyncio
import pyinotify
import signal
import time

MAIL_RCP="foo@example.com"
directories = [
    '/var/www/site1/public/.well-known/',
    '/var/www/site1/public/.well-known/acme-challenge/',
    '/var/www/site2/public/.well-known/',
    '/var/www/site2/.well-known/acme-challenge/',
    '/var/www/site3/public/.well-known/',
    '/var/www/site3/public/.well-known/acme-challenge/'
]

events = []
lock = asyncio.Lock()

async def signal_handler(signame):
    notifier.stop()
    loop.stop()

async def send_mail():
    global events
    while True:
        await asyncio.sleep(10)
        async with lock:
            if events:
                message = ("Der Inhalt der '/.well-known/'-Verzeichnisse wurde verändert "
                           "- Liste der Events:\n"
                           f'{chr(10).join(f"{ts}: {event.maskname} {event.pathname}" for ts, event in events)}'
                           "\n")
                events.clear()
            else:
                continue
        proc = await asyncio.create_subprocess_exec(
                "/usr/bin/mailx", "-s", "Achtung: Inhalt von /.well-known/ geändert", MAIL_RCP,
                stdin=asyncio.subprocess.PIPE)
        await proc.communicate(input=message.encode())

async def add_event(event):
    global events
    async with lock:
        events.append((time.time(), event))

def handle_read_callback(event):
    loop.create_task(add_event(event))

loop = asyncio.get_event_loop()
wm = pyinotify.WatchManager()
notifier = pyinotify.AsyncioNotifier(wm, loop, default_proc_fun=handle_read_callback)

mask = pyinotify.IN_DELETE | pyinotify.IN_CREATE | pyinotify.IN_MODIFY | pyinotify.IN_MOVED_TO
for d in directories:
    wm.add_watch(d, mask)

loop.create_task(send_mail())

for signame in ('SIGINT', 'SIGTERM'):
    loop.add_signal_handler(getattr(signal, signame),
                            lambda: asyncio.ensure_future(signal_handler(signame)))

loop.run_forever()

dingsbums

Anmeldungsdatum:
13. November 2010

Beiträge: 3790

inotifywait --daemon --timefmt "%Y-%m-%d %H:%M:%S" --format "%T  %e %w%f" -e create,delete,move,modify --outfile /pfad/zum/logfile /pfad/zu/ueberwachen

loggt Änderungen in /pfad/zu/ueberwachen nach /pfad/zum/logfile. Da tauchen dann auch Ereignisse auf wie

touch datei && rm datei

Vielleich hilft das irgendwie weiter.

Tronde Team-Icon

(Themenstarter)
Avatar von Tronde

Anmeldungsdatum:
23. November 2006

Beiträge: 1640

Hallo und danke für eure Antworten.

@seahawk1986: Du machst mir nicht gerade Mut. Das von dir veröffentlichte Python-Skript kann ich nachvollziehen und es scheint für diesen Zweck hinreichend zu sein. Grundsätzlich gefällt mir die Idee nicht so gut, diese Skripte selbst zu schreiben und sie in meiner Umgebung zu verteilen und zu pflegen. Dafür wirkt mir das Skript einfach zu umfangreich.

Auf meinem privaten Server mag das noch in Ordnung sein. Beruflich erwarte ich, dass mir meine Distribution diese Arbeit abnimmt und ein Tool für diese Zwecke bereitstellt.

Falls du allerdings motiviert bist aus deinem Skript ein Projekt zu machen, welches Pakete für DEB- und RPM-Distributionen bereitstellt, welches einen konfigurierbaren Dienst inkl. Manpage bereitstellt, stehen die Chancen gut, dass ich es nutze. 😎

Allerdings macht das Upstream-Projekt auch nicht den Eindruck noch besonders aktiv zu sein. Da habe ich ein wenig die Angst auf ein totes Pferd zu setzen.

@dingsbums: Dein Vorschlag mutet deutlich schlanker an. In diesem Fall würde ich die Path Unit nutzen, um mich informieren zu lassen, wenn sich die Logdatei geändert hat. Nur muss ich mich dann wieder darum kümmern, dass der Dienst läuft bzw. ich erfahre, wenn er verreckt ist. Obowhl ich das evtl. lösen kann, wenn ich eine einfache Service Unit dafür erstelle, welche dieses Kommando ausführt.

Eine Lösung, die mich zufrieden stellt, ist leider noch nicht dabei. Dennoch bedanke ich mich für eure Antworten und Lösungsvorschläge bis hier hin. Mein konkretes Problem kann ich damit lösen. Ich lasse das Thema noch auf ungelöst stehen, in der Hoffnung, dass es noch weitere Vorschläge gibt.

MfG
Tronde

seahawk1986

Anmeldungsdatum:
27. Oktober 2006

Beiträge: 11260

Wohnort: München

Tronde schrieb:

Beruflich erwarte ich, dass mir meine Distribution diese Arbeit abnimmt und ein Tool für diese Zwecke bereitstellt.

Fürs Auditing gibt es ja eigentlich schon Tools wie auditd (ist nicht auf RedHat beschränkt, aber immerhin dokumentieren die es recht ausgiebig, dass man es nutzen kann):

Falls du allerdings motiviert bist aus deinem Skript ein Projekt zu machen, welches Pakete für DEB- und RPM-Distributionen bereitstellt, welches einen konfigurierbaren Dienst inkl. Manpage bereitstellt, stehen die Chancen gut, dass ich es nutze. 😎

Ich lasse das mal als Proof of Concept stehen (das war ja vorwiegend dafür gedacht um ein bisschen mit asyncio zu spielen), Enterprise-tauglichen Code überlasse ich anderen. Wenn man das ernsthaft und besonders langlebig machen will, dann baut man das doch eh in einer Sprache wie C oder C++ unter direkter Nutzung der inotify-API des Kernel, das ist dann langfristig stabil und skaliert auch besser, wenn einem Schadcode das Dateisystem umpflügt 😬

Allerdings macht das Upstream-Projekt auch nicht den Eindruck noch besonders aktiv zu sein. Da habe ich ein wenig die Angst auf ein totes Pferd zu setzen.

Es gibt noch andere Bibliotheken, die inotify für Python bereitstellen - ich habe auf die Schnelle pyinotify genommen, weil es in den Paketquellen für alle noch unterstützten Ubuntu-Versionen ist und mit asyncio funktioniert.

Tronde Team-Icon

(Themenstarter)
Avatar von Tronde

Anmeldungsdatum:
23. November 2006

Beiträge: 1640

Guten Morgen,

ich stimme dir zu, dass man auch mit dem Audit-System eine entsprechende Überwachung einrichten kann und die Ereignisse dann protokolliert werden. Jedoch gibt es auch hier keine Möglichkeit der automatischen Benachrichtigung via E-Mail o.ä.

Hier ist dann erst das Log zu parsen und eine Benachrichtigungsfunktion drumherum zu stricken.

Wie dem auch sei, dank euch weiß ich mir nun erstmal zu behelfen. Darüber hinaus habe ich gemäß den systemd Contribution Guidelines einen Bugzilla bei Red Hat geöffnet.

Danke nochmal und ein schönes Wochenende!

seahawk1986

Anmeldungsdatum:
27. Oktober 2006

Beiträge: 11260

Wohnort: München

Tronde schrieb:

Hier ist dann erst das Log zu parsen und eine Benachrichtigungsfunktion drumherum zu stricken.

Soweit ich das gelesen habe, kann man sich auch mit audisp an auditd dran hängen und dann die für den Anwengunsfall interessanten Events direkt verwerten: https://security-plus-data-science.blogspot.com/2017/04/sending-email-when-audisp-program-sees.html - in dem Blog gibt es auch noch einen Artikel, der genauer beschreibt, wie so ein audisp-Plugin funktioniert (https://security-plus-data-science.blogspot.com/2017/04/writing-basic-audispd-plugin.html), da müsste mal also in beliebigen Sprachen geschriebene Programme dran hängen können, solange die sich an die Vorgaben halten.

Es gibt auch fertige Plugins (https://www.mankier.com/package/audispd-plugins), die z.B. die Events von auditd ins Syslog umleiten können, so dass man da mit den gängigen Tools für Email-Benachrichtigungen bei Auffälligkeiten im Syslog arbeiten könnte.

Antworten |