Von Null nach SNMP
Ich bin auf der Suche nach einem Monitoring Plugin für den Spam- und Virenfilter für Mails rspamd. Das ist ziemlich ernüchtern da ich außer dem check_tcp auf die verwendeten Ports nichts gefunden habe. (mehr …)
Ich bin auf der Suche nach einem Monitoring Plugin für den Spam- und Virenfilter für Mails rspamd. Das ist ziemlich ernüchtern da ich außer dem check_tcp auf die verwendeten Ports nichts gefunden habe. (mehr …)
Fail2ban ist ein nützliches Werkzeug und ich habe ja schon einmal darüber geschrieben: fail2ban und dynamische IP-Adressen. Heute mal ein etwas anderes Thema welches mich beruflich ebenfalls häufig bewegt: Monitoring.
Also wie würde man vorgehen wenn man einen Check für Nagios, Icinga2, Shinken, ... braucht? Man sucht in der Suchmaschine des Vertrauens oder bemüht eine der Plugin-Sammlungen im Internet. Doch halt, ein Blick ins Repository von fail2ban verrät das ein passender Check bereits mitgebracht wird: https://github.com/fail2ban/fail2ban/tree/master/files/nagios.
Das ist ja mal richtig super 🙂 Was mir jetzt weniger gefällt ist die Ausgabe der Performance-Daten:
CHECK FAIL2BAN ACTIVITY - CRITICAL - 6 detected jails with 195 current banned IP(s) | apache.currentBannedIP=0 dovecot.currentBannedIP=0 fail2ban.currentBannedIP=0 postfix.currentBannedIP=0 roundcube.currentBannedIP=0 sshd.currentBannedIP=195
Viele Monitoringinstallationen die ich betreue verwenden zur Visuallisierung rrd basierte Systeme wie zum Beispiel PNP4Nagios (http://docs.pnp4nagios.org/start). Das ist jetzt weniger toll, da sich bei mir durchaus auch mal die Anzahl der jails ändern kann. Zweitens sind mir diese Daten eigentlich egal, viel interessanter finde ich die Anzahl der Jails sowie die aktuell geblockten IPs. Das täte mir reichen.
Naja, dann also mal in den Quellcode rein geschaut. Die passende Stelle sollte sich finden lassen. Ist in Python geschrieben. Das ist jetzt nicht so meins, aber so eine kleine Änderung/Ergänzung bekomme ich allemal hin. Ich hab ja schon das ein oder andere kleinere Skript in Python geschrieben. Doch halt, Moment: Der Nagios Check ist in perl geschrieben. Das ist jetzt allerdings sehr meins. Kurz den Code angelesen und tada, fertig. Nun in einen Pull Request gepackt und fertig: https://github.com/fail2ban/fail2ban/pull/2732.
Meine Ausgabe sieht jetzt so aus:
CHECK FAIL2BAN ACTIVITY - CRITICAL - 6 detected jails with 195 current banned IP(s) | jails=6 currentBannedIp=195
Die alte Ausgabe möchtest Du zusätzlich haben? Das geht natürlich ebenfalls:
CHECK FAIL2BAN ACTIVITY - CRITICAL - 6 detected jails with 195 current banned IP(s) | jails=6 currentBannedIp=195 apache.currentBannedIP=0 dovecot.currentBannedIP=0 fail2ban.currentBannedIP=0 postfix.currentBannedIP=0 roundcube.currentBannedIP=0 sshd.currentBannedIP=195
Oder man lässt alles so wie es ist, das geht selbstverständlich weiterhin 😛
Hier der Link zu meiner Variante von check_fail2ban: https://github.com/SteScho/fail2ban/tree/master/files/nagios.
Nextcloud zeigt einem in der Verwaltung an ob es Updates gibt. Nur mag ich hier nicht immer nachsehen müssen, zumal ich viele Nextcloud-Instanzen zu verwalten habe. Die Logik dahinter müsste man doch für einen Monitoring-Check verwenden können. Alternativen? Bisher habe ich keine gefunden deren Funktionsweise mich überzeugt oder der über einen längeren Zeitraum problemlos funktioniert hätte. Es muss also eine eigene Lösung her!
Ich würde jetzt einfach mal vermuten, dass jeder der diesen Artikel tatsächlich liest Nextcloud kennt. Oder zumindest ownCloud. Sicherheitshalber nochmal nachschauen? Bitte, das geht hier https://nextcloud.com/ bzw. hier https://owncloud.org/. Da ich selbst inzwischen nur noch wenig mit ownCloud zu tun habe und fast alle Installation mit Nextcloud betreibe beziehe ich mich in diesem Blogbeitrag ausschließlich auf Nextcloud.
Wie in einem anderen Blogbeitrag beschrieben mag ich keine Mails welche mich auf verfügbare Updates hinweisen (Statusmails? Nein Danke!). Das wären schlichtweg zu viele Systeme die sich da innerhalb kürzester Zeit melden würden. Ebenso, auch wenn das für eine Plattform reichen täte, bin ich kein Fan davon in Nextcloud nachzusehen. Wenn es für die erste installierte Plattform Updates gibt, dann auch für alle anderen. Unterm Strich viel zu mühsam. Zumal wir auch Kunden haben die Ihre Cloud-Installation selbst betreuen. Hier könnte der Check als Hinweis für den Kunden dienen. Oder für mich als Serverbetreiber Grund genug sein mal wieder den Telefonhörer in die Hand zu nehmen und den Kunden gefühlvoll mit dem notwendigen Nachdruck davon zu überzeugen doch bitte Updates zu installieren. Sicherheit und so. Klappt richtig gut 😉

status.php Ausgabe von Nextcloud.
Bleibt die Frage wie prüfen. Ein paar Checks habe ich gefunden welche die lokale Version ermitteln in dem Sie die version.php-Datei im Dateisystem direkt auslesen oder einfach https://<deine.nextcloud>/status.php aufrufen. In diesem JSON-String findet sich die Versionsnummer. Eine aufbereitete Fassung der JSON-Daten siehst Du links im Screenshot. So oder so, der Teil mit der lokalen Versionsnummer ist leicht. Bleibt noch die Frage wie man heraus findet ob es überhaupt Updates gibt. Hierfür habe ich einige verschiedene Ansätze gefunden:
private function getUpdateServerResponse() {
$this->silentLog('[info] getUpdateServerResponse()');
$updaterServer = $this->getConfigOption('updater.server.url');
if($updaterServer === null) {
// FIXME: used deployed URL
$updaterServer = 'https://updates.nextcloud.org/updater_server/';
}
$this->silentLog('[info] updaterServer: ' . $updaterServer);
$releaseChannel = $this->getCurrentReleaseChannel();
$this->silentLog('[info] releaseChannel: ' . $releaseChannel);
$this->silentLog('[info] internal version: ' . $this->getConfigOption('version'));
$updateURL = $updaterServer . '?version='. str_replace('.', 'x', $this->getConfigOption('version')) .'xxx'.$releaseChannel.'xx'.urlencode($this->buildTime).'x'.PHP_MAJOR_VERSION.'x'.PHP_MINOR_VERSION.'x'.PHP_RELEASE_VERSION;
$this->silentLog('[info] updateURL: ' . $updateURL);
// Download update response
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_URL => $updateURL,
CURLOPT_USERAGENT => 'Nextcloud Updater',
]);
In Zeile 7 ist der Update-Server angegeben und in Zeile 15 findet sich der Aufbau der URL. Einige dieser Bestandteile finden sich in der bereits angesprochenen version.php, der Rest sind Versionsnummern der lokal verwendeten PHP-Installation. Dies wird mit reichlich "x" getrennt zu einer langen URL zusammen gesetzt welche z.B. so aussieht:
Diese Adresse geöffnet ergibt folgende Antwort:
<?xml version="1.0" encoding="UTF-8"?> <nextcloud> <version>15.0.0.10</version> <versionstring>Nextcloud 15.0.0</versionstring> <url>https://download.nextcloud.com/server/releases/nextcloud-15.0.0.zip</url> <web>https://docs.nextcloud.com/server/15/admin_manual/maintenance/upgrade.html</web> <changes>https://updates.nextcloud.com/changelog_server/?version=15.0.0</changes> <autoupdater>1</autoupdater> <eol>0</eol> <signature>c4llfwhYTKaEiTWVivJ1NgTIS5q2mxJVJkyew0nd/setTzpXt2H9zXKGQLmjUcy7 fSeW5+wkUfGD2J3XrcLKifGZMjxrhtAW97L1g/o8gp84ZO1WbrOKfneTLDXWkmwg nztf/5z0F0nppOyUX6HR84UhwDbhET7U8JV/1Ik7OO6D361U4sxELUhvg6GyQbdS oJ/t4MvMe1Fs+F5Q7dZzczivxu5oB0n2cVu9WMh8VnV6MiYcKV4/w7poibHMO16k 4IHl6E2hTF3un0obMKy7SRY4xXJ0Ohmj5Ne/8iDRjM7oop5Tzpnf1nPLEJJOZPSN fq4UospVzAmRe4UGPTUiqQ==</signature> </nextcloud>
In diesem Beispiel ist die Version 15.0.0.10 als aktuellere Version zur angefragten 14.0.4.2 verfügbar. Falls keine xml-Datei ausgeliefert wird ist die Nextcloud Installation auf aktuellem Stand.
Das war es mit dem Verfahren zur Prüfung ob es Updates gibt. Bleibt noch die Umsetzung über. Obwohl dies sehr einfach in PHP selbst zu realisieren wäre ist bei mir die Wahl auf Python3 gefallen. Ich wollte schon längst mal wieder was in Python machen um meine angestaubten Python-Kenntnisse aufzufrischen und vor allem zu vertiefen. Also wurde die Sprache der Wahl die aktuelle Version von Python3. Die versions.php ist eine relativ einfach PHP-Datei welche sich gut auslesen lassen sollte. Fehlen noch die benötigten PHP-Versionsnummern. Ein an dieser Stelle gern genommener Trick ist in der vermeintlichen anderen Sprache die benötigten Daten in ein Array zu packen und dieses per JSON auszugeben. Die so umgewandelten Daten lassen sich dann super weiterverarbeiten:
ncVersion = json.loads(subprocess.check_output([
args.php, '-r',
'include \'' + args.file + '\';' + '''
$g = array();
foreach($GLOBALS as $key => $val) {
if(preg_match('/^OC_/', $key)) {
$g[$key] = $val;
}
}
echo json_encode(
array(
'pv' => PHP_VERSION,
'pmav' => PHP_MAJOR_VERSION,
'pmiv' => PHP_MINOR_VERSION,
'prv' => PHP_RELEASE_VERSION,
'g' => $g
)
);
'''
]))
Noch ein kleiner Tipp für alle die PHP an der Stelle nicht so gut kennen: Man könnte einfach das Array $GLOBALS ausgeben, da wären alle Werte drin. Nur gibt es in $GLOABLS eine Referenz auf sich selbst da ja auch $GLOBALS eine globale Variable ist. Und an genau der Stelle steigt json_encode() aus da diese Funktion mit Referenzen nicht umgehen kann. In der versions.php fangen aber alle interessanten Variablen mit "OC_" an und lassen sich somit super filtern ;-).
Den kompletten Check, eine Makro gestützte Beispiel-Konfig für Icinga2 sowie eine kurze Anleitung findet Ihr in meinem GitLab-Account: https://gitlab.com/Gehirn-Mag.net/icinga-and-nagios-plugins/. Bis jetzt liegt da nur der Nextcloud-Update-Check drin, weitere werden aber folgen.
Und so sieht das dann im icingaweb2 aus:

check_nextcloud.py Ausgabe in icingaweb2
Was jetzt noch fehlt ist die Prüfung der Addons auf Aktualität. Auch hierfür sollte sich der passende Anfragestring irgendwo im Quellcode von Nextcloud finden lassen. Mir reicht jedoch vorerst die Prüfung von Nextcloud selbst. Ich bin also vorerst zufrieden. Wer weiß, ggf. reiche ich in ein paar Wochen die Erweiterung für die Addons nach.
Viel Spaß beim benutzen. Feedback und Anregungen gerne via Mail oder hier in den Kommentaren hinterlassen.
An dieser Stelle sind alle Dinge gesammelt die sich seit der Erstellung des Checks und des obigen Beitrages geändert haben. Sollte es zu viel werden wird dieser Beitrag als veraltet markiert und ein neuer verfasst. Bis dahin gilt diese Übersicht.
Es ist möglich den Update Channel in Nextcloud zu ändern. Diese Einstellung findet sich jedoch nicht in der versions.php sondern in der config/config.php. Sollte dort der Channel definiert sein wird dieser verwendet, ansonsten der aus der versions.php. Das hat jedoch zur Folge, dass via -c jetzt noch zusätzlich die config.php mit angegeben werden muss.
Anmerkung zur Icinga Config: Die config.php darf vermutlich vom Benutzer welcher Icinga ausführt nicht gelesen werden. Deswegen ist im CheckCommand ein Aufruf von sudo mit enthalten.
Bei Python Versionen bis 3.5.x erscheint die Fehlermeldung "CRITICAL Cannot parse file /var/www/nextcloud/version.php". Ab Version 3.6 ist dieses Problem behoben.
Falls kein Update auf Pyhton 3.6.x möglich ist kann der Check wie folgt angepasst werden:
// Die import Liste um chardet erweitern - muss ggf. vorher noch installiert werden
import chardet
// Den ersten try: Block wie folgt bearbeiten
try:
jsonResponse = subprocess.check_output([
args.php, '-r',
'include \'' + args.file + '\';include \'' + args.config + '\';' + '''
$g = array();
foreach($GLOBALS as $key => $val) {
if(preg_match('/^(OC_|CONFIG$)/', $key)) {
$g[$key] = $val;
}
}
echo json_encode(
array(
'pv' => PHP_VERSION,
'pmav' => PHP_MAJOR_VERSION,
'pmiv' => PHP_MINOR_VERSION,
'prv' => PHP_RELEASE_VERSION,
'g' => $g
)
);
'''
])
print(jsonResponse)
ncVersion = json.loads(jsonResponse.decode(chardet.detect(jsonResponse)['encoding']))