Cron und Logrotate: Ein Beispiel anhand eines Spieleservers

Genauso unabdingbar wie Liebe und guter Wein für Goethe waren, sind Cron und Logrotate das Lebenselixier für jeden Serveradmin. Vielleicht etwas übertrieben formuliert, aber auch nur fast. 🙂 Als "normaler" Linuxnutzer kommt man nur sehr selten direkt mit den beiden in Berührung, da in der Regel einfach alles läuft.
Nur am Rande bemerkt: Wer an Debians und Ubuntus "Popularity Contest" teilnimmt und ihn nicht auf einem Server laufen lässt, sollte auf jeden Fall noch anacron installiert haben, da das Senden der Berichte zu wechselnden Tageszeiten erfolgt und man unter Umständen den Rechner dann nicht eingeschaltet hat, weswegen der Cron-Job nicht ausgeführt werden kann.
Im Gegensatz zu Anacron arbeitet Cron präzise zu einem bestimmten Zeitpunkt Aufträge ab und setzt damit voraus, dass der Rechner kontinuierlich verfügbar ist. Im Zusammenspiel mit Logrotate, das Logdateien nach einem vorgegebenen Zeitintervall verschieben und komprimieren kann, ist er äußerst wichtig und nützlich für jeden Server.

Logrotate-Beispiel anhand von OpenArena

Der OpenArena-Server speichert den Verlauf der Spiele in der Logdatei games.log. Hierfür habe ich eine neue Konfigurationsdatei in /etc/logrotate.d/ angelegt, die wie folgt aufgebaut ist.

/home/openarena/.openarena/baseoa/games.log {
        daily
        missingok
        rotate 14
        compress
        delaycompress
        notifempty
        create 644 openarena openarena
        sharedscripts
        postrotate
                if [ -x /usr/sbin/invoke-rc.d ]; then
                        invoke-rc.d oa_ded restart > /dev/null 2>&1;
                else
                        /etc/init.d/oa_ded restart > /dev/null 2>&1;
                fi;
        endscript
}

Die Syntax ist sehr logisch.

  • Wann soll rotiert werden? Alternativen sind weekly und monthly
  • daily

  • Sollte die Logdatei nicht vorhanden sein, ignoriere den Fehler und gehe zur nächsten Datei.
  • missingok

  • Wie oft werden Logdateien rotiert? In diesem Fall werden für jeden Tag für insgesamt 14 Tage Logdateien vorgehalten. Am 15. Tag würde also die älteste Logdatei überschrieben werden. Wäre z.B. weekly und rotate 8 eingestellt, würde die Logdatei jede Woche für insgesamt 8 Wochen rotiert.
  • rotate 14

  • Um Platz zu sparen sollten die Dateien mit gzip komprimiert werden.
  • compress

  • Verzögere die Kompression um einen Rotationszyklus, da manche Programme noch in die letzte Logdatei schreiben können. Dadurch ist games.log.1 immer unkomprimiert.
  • delaycompress

  • Wenn die Datei leer ist, soll gar nichts gemacht werden.
  • notifempty

  • Eine neue games.log wird automatisch mit den Dateirechten 644 und Benutzer und Gruppe openarena erzeugt.
  • create 644 openarena openarena

  • Normalerweise wird die Anweisung prerotate und postrotate bei jeder Logdatei ausgeführt, also wenn anstelle von games.log z.B. eine Wildcard wie *.log angegeben worden wäre. In diesem Fall nicht entscheidend, sondern nur zur Sicherheit.
  • sharedscripts

  • Mit dem letzten Kommando postrotate kann eine Aktion nach der durchgeführten Logrotation ausgeführt werden. In meinem Fall starte ich danach den Server immer neu. Das hat den zusätzlichen Vorteil, dass eventuell durch Spieler geänderte Servervariablen wieder auf die Standardwerte zurückgesetzt werden. Für den Teeworlds-Server war ein Neustart sogar notwendig, da er ansonsten nicht in die neue Logdatei geschrieben hat.

Weitere Ideen und Anregungen finden sich im Verzeichnis /etc/logrotate.d/ und natürlich mit man logrotate. Die Konfigurationsdatei für logrotate ist /etc/logrotate.conf.

Cron in Kürze

Cron ist das Herzstück jedes Servers. Er arbeitet zeitgesteuert alle Shellskripte in /etc/cron.hourly, /etc/cron.daily, /etc/cron.weekly und /etc/cron.monthly ab und wertet die Informationen in /etc/crontab und den jeweiligen crontabs aus. Cron muss nicht neugestartet werden, wenn eine Einstellung verändert wird.
In meiner /etc/crontab habe ich z.B so etwas stehen:

 05 7    * * *   openarena       /usr/local/bin/oa_stats_daily.sh > /dev/null 2>&1

Hier wird mit den Rechten des Benutzers openarena ein kleines Skript ausgeführt, welches die täglichen Statistiken um 7 Uhr und fünf Minuten für OpenArena generiert.
Mehrere Beispiele für Cron aus der Wikipedia:

#M    S   T   M  W    Befehl
5     *   *   *  *    /usr/bin/message.sh     #Befehl wird fünf Minuten nach jeder vollen Stunde aufgerufen.
*/5   *   *   *  *    /usr/bin/message.sh     #Befehl wird alle 5 Minuten aufgerufen (die Schrittweite wird durch */Schrittweite angegeben).
59    23  *   *  0    gzip /var/log/messages  #Befehl wird einmal pro Woche sonntags um 23:59 Uhr ausgeführt.
0     0   *   *  *    gzip /var/log/auth.log  #Befehl wird täglich um 00:00 Uhr ausgeführt.
20,30 1   *   *  1-5  /usr/bin/work.sh        #Befehl wird montags bis freitags jeweils um 01:20 und 01:30 ausgeführt.
0     1   1-7 12 1    /usr/bin/work.sh        #Befehl wird am 1. bis 7. Dezember sowie an jedem Montag im Dezember um ein Uhr nachts ausgeführt.

Aus Sicherheitsgründen kann man die Erlaubnis für Cron-Jobs einschränken, indem eine Datei /etc/cron.allow mit den berechtigten Benutzern angelegt wird. (Ein Name pro Zeile). Ansonsten darf jeder Benutzer mit Eingabe von crontab -e seine eigenen Aufträge anlegen.
Cron bietet damit neben seinen typischen Aufräum- und Prüfarbeiten die Möglichkeit eigene Skripte zeitlich gesteuert auszuführen. In Zusammenspiel mit Logrotate lassen sich so ganz leicht Statistiken für den Spieleserver generieren, sofern das Spiel diese überhaupt mitloggt. Zu dem genauen Inhalt des Skripts ein anderes Mal mehr.

Links

http://de.wikipedia.org/wiki/Cron
http://linux.die.net/man/8/cron
http://www.debian-administration.org/articles/56

Chronicle: Bloggen mit dem Blogkompilierer

Chronicle ist ein sogenannter Blogkompilierer, der aus einfachen Textdateien, Markdown und HTML ein vollständiges Blog mit Schlagworten, Archiv und RSS-Feeds erstellen kann. Ich hatte ursprünglich vorgesehen alle Webseiten von Hand zu erstellen, da linuxiuvat.de hauptsächlich zur Beschreibung von Spielen, Dokumentation und für Statistiken gedacht ist, für die ein CMS mit dynamischen Inhalten über das Ziel hinaus schießen würde. Auf die Idee nach einem statischen Webseitengenerator wie Chronicle zu suchen, hat mich ein Kommentator gebracht, der gerne mit Hilfe eines RSS-Feeds auf dem Laufenden bleiben wollte.
Wie man Chronicle konfiguriert und bedient, darum geht es in diesem Beitrag.

Installation und Konfiguration

aptitude install chronicle


Es gibt zwei Möglichkeiten Chronicle zu verwenden. Man kann den Blogkompilierer entweder direkt auf dem vServer installieren oder ebenso praktisch auf dem eigenen Rechner zu Hause und verschiebt dann die generierten Seiten per FTP/SSH zum Webserver. Die Einstellungen werden global entweder in /etc/chroniclerc oder für jeden Benutzer einzeln in ~/.chroniclerc vorgenommen.

# Hiervon werden die Blogeinträge gelesen
input = /home/apo/blog/input
# In diesem Verzeichnis liegt später das fertige Blog
output = /home/apo/blog/news
# Name des Themas. Die Themen liegen in /usr/share/chronicle/themes
theme = default
# Anzahl der Blogeinträge auf der Startseite
entry-count = 10
# Anzahl der RSS-Einträge
rss-count = 10
# Wir schreiben die Artikel in HTML. Alternativen sind Markdown und Textile
format = html
# Kommentarfunktion einschalten
no-comments = 0
# Der Name des Blogs
blog_title = Linux iuvat /news

Die Standardeinstellungen sind sinnvoll und es gibt nur noch wenige zusätzliche Optionen. Um einen Blogartikel zu erstellen, genügt es eine Textdatei im Input-Ordner mit dem folgendem Format zu erstellen.

Title: Hallo Welt
Tags: Neuigkeiten, Debian, Ubuntu
Date: 21st April 2012
<h2>Wichtige Nachrichten</h2>
<p>Mein Blog ist online!</p>

Lediglich die Datumsangaben müssen in englischer Notation erstellt werden. Die Ausgabe kann aber mit der Option --lang=german angepasst werden.
Nachdem auf die gleiche Weise alle Blogartikel geschrieben wurden, wird das gesamte Blog mit
chronicle
generiert und landet im vorher definierten Output-Verzeichnis.

Kommentare

Wie im letzten Artikel erwähnt, ist der Nachteil eines statischen Webseitengenerators, dass eine Kommentarfunktion entweder extern ausgelagert oder serverseitige Skripte zusätzlich installiert werden müssen. Im Falle von Chronicle wird aber schon ein CGI-Skript mitgeliefert, dass es möglich macht Kommentare zu verfassen. Diese werden in einer Textdatei gespeichert und beim Neukompilieren des Blogs in die statischen Seiten integriert.
Drei Einstellungen sind in der comments.cgi zu ändern.

my $COMMENT = "/var/www/comments/"
my $TO = 'root@localhost';
my $FROM = 'www-data@vps.example.com';

Der Ordner in dem die Kommentare gespeichert werden, sollte aus Sicherheitsgründen außerhalb des Webserver-Root-Verzeichnisses liegen. Die Benachrichtigungsadresse lässt sich beliebig wählen. Anschließend muss die Datei nur noch in das CGI-Verzeichnis des Webservers kopiert werden. Wer z.B. Lighttpd benutzt, kann das entsprechende CGI-Modul mit
lighty-enable-mod cgi
aktivieren. Zusätzlich muss noch folgendes bedingtes Konstrukt zur Konfiguration in der lighttpd.conf oder /etc/lighttpd/conf-available/10-cgi.conf hinzugefügt werden.

$HTTP["url"] =~ "^/cgi-bin/" {
cgi.assign = ( "" => "/usr/bin/perl" )
}

Die Kommentare werden mit dem Befehl
chronicle --comments=Pfad_zum_Kommentar_Ordner
eingebunden. Es gibt verschiedene Ansätze wie man dem Spamproblem entgegnen kann. Da ich bisher noch keine Probleme damit hatte, ein anderes Mal mehr dazu.

Fazit

Einige Ideen wie Chronicle aussehen kann, findet ihr im Blog des Machers, Steve Kemp, auf der Homepage von Kai Wasserbäch oder auf meiner News-Seite bei linuxiuvat.de.
Die Themen lassen sich mit etwas HTML-Kenntnissen gut anpassen. Chronicle ist schlicht, aber dadurch meiner Meinung auch einfach zu erlernen. Man erhält mit lediglich einem Befehl ein vollständiges Blog mit Schlagworten, Feeds und Archiven, dass ressourcenschonend und schnell ist. Wem das noch nicht zusagt, sollte auch einen Blick auf die Alternativen werfen.

Logdateien von Lighttpd auswerten mit Awstats und Awffull

Neben dem ausgezeichneten Piwik existieren zur Darstellung von Benutzerstatistiken und Auswertung von Logdateien noch eine Reihe von sogenannten Log-Analysierern. Da ich die Installation von PHP und MySQL möglichst vermeiden wollte, habe ich mir zwei altbekannte Helfer aus diesem Bereich näher angeschaut. Hier stehen nur noch einmal die wichtigsten Einstellungen, die ich verändert habe und ein kurzes Fazit.

Awstats

Das war meine erste Wahl, da mich die vielfältigen Funktionen auf der Webseite des Projekts überzeugt hatten. Awstats ist hauptsächlich in Perl geschrieben und lässt sich mit Hilfe eines CGI-Skripts in Echtzeit aktualisieren. Diese Funktionalität benötigte ich aber gar nicht und habe deshalb alle Statistikseiten mit Hilfe des mitgelieferten Skripts buildstatic.sh statisch generieren lassen. Die Funktion lässt sich in /etc/default/awstats aktivieren.
Die Konfiguration findet bei Debian z.B. in /etc/awstats/awstats.linuxiuvat.de.conf statt. Man sollte die Standardkonfiguration von awstats.conf für sein eigenes Projekt dementsprechend umbenennen und nach /etc/awstats kopieren. Debian erstellt dann automatisch verschiedene Unterordner in /var/cache/awstats/ auf Basis des Dateinamens. Um die Statistiken später darstellen zu können, müssen diese Ordner für euer gewünschtes Webserver-Verzeichnis freigegeben werden.
Die Konfiguration von Awstats ist äußerst gut dokumentiert. Die meisten Standardeinstellungen konnte ich beibehalten. Lediglich diese hier habe ich geändert oder sind erwähnenswert.

# Pfad zur Logdatei
LogFile="/var/log/lighttpd/linuxiuvat.de/access.log"
# Webserver-Log deshalb Typ W
LogType=W
# Apache Logformat funktioniert auch mit Lighttpd
LogFormat=1
# Eure Domain und Aliase
SiteDomain="linuxiuvat.de"
HostAliases="linuxiuvat.de www.linuxiuvat.de localhost 127.0.0.1"
# Wir wollen die Namen der IP-Adressen nicht auflösen, weil es die Generierung der Statistiken verlangsamt
DNSLookup=0
# Reguläre Ausdrücke können unerwünschte Begriffe oder Benutzeragenten herausfiltern
SkipUserAgents="REGEX[Python-urllib]"
# Awstats lässt sich durch eine Vielzahl von Plugins erweitern. Mit GeoIP lässt sich die Herkunft der Besucher anzeigen
LoadPlugin="geoipfree"

Damit die IP-Adressen nach Ländern aufgelöst werden können, muss entweder die Bibliothek libgeo-ipfree-perl oder libgeo-ip-perl zusätzlich installiert werden.

Statische Seiten generieren und ein kleiner Hack

Debian stellt in /usr/share/awstats/tools/ mit buildstatic.sh ein Skript zur Verfügung, welches zum einen separate Awstats-Unterordner basierend auf den Konfigurationsdateien erstellt und zum anderen awstats_buildstaticpages.pl aufruft.
Die Statistiken werden in weiteren Ordnern nach Monaten sortiert. Damit jeder dieser Monats-Ordner noch eine index.html Datei erhält, muss dieser kleine Codeschnipsel am Ende der Datei hinzugefügt werden.

print "$cpt files built.n";
print "Main HTML page is 'awstats.$OutputSuffix.$StaticExt'.n";
my $command="/bin/cp $OutputDir" . "awstats.$OutputSuffix.$StaticExt $OutputDir" . "index.html";
$retour=`$command 2>&1`;
if ($QueryString =~ /(^|-|&)buildpdf/i) { print "PDF file is 'awstats.$OutputSuffix.pdf'.n"; }
0; # Do not remove this line

Den Tipp habe ich in diesem PDF-Dokument gefunden. Entscheidend ist die Zeile, die mit my $command beginnt und die normale Startseite in index.html umwandelt.
Zusätzlich sollte man noch einen Blick in /etc/cron.d/ werfen und überprüfen, wie oft Awstats und das zugehörige Update-Skript ausgeführt werden sollen. Mir genügte die tägliche Generierung der Statistiken.

Awffull

Awffull ist eine Abspaltung von Webalizer, die einige Verbesserungen mit sich bringt. Awffull ist noch einfacher einzurichten. Es genügt ein typisches
aptitude install awffull
und ein paar Veränderungen in /etc/awffull/awffull.conf.

# Pfad zur Logdatei
LogFile /var/log/lighttpd/linuxiuvat.de/access.log
# Auflösung der IP-Adressen nach Herkunftsland
GeoIP yes
# Pfad zur GeoIP-Datenbank
GeoIPDatabase /usr/share/GeoIP/GeoIP.dat
# 404 - Fehler anzeigen lassen.
Top404Errors 10

Die GeoIP-Datenbank für GeoIP ist frei und kostenlos und kann von maxmind.com heruntergeladen werden.
Sollten die Logdateien sehr groß sein, sollte man in Erwägung ziehen Incremental auf yes zu setzen. Für ein kleines Projekt wie linuxiuvat.de ist das aber (noch) unnötig. 🙂
Die HTML-Dateien mit den Statistiken befinden sich danach in /var/www/awffull/.

Fazit

Beide Werkzeuge erfüllen vollkommen ihren Zweck. Awstats hat mehr Funktionen, ist umfangreicher und lässt sich auch in Echtzeit per CGI-Skript aktualisieren. Awffull ist schlichter, sehr schnell und einfach einzurichten. Ich habe mich schließlich für Awffull entschieden, da für mich der Informationsgehalt vollkommen ausreichend ist. Piwik bietet zusätzlich z.B. noch Angaben über die Bildschirmauflösung und eine Echtzeitfunktion, die ein Programm zur reinen Loganalyse natürlich nicht liefern kann. Für jedes kleine Projekt tun es aber bedenkenlos auch Awstats und Awffull.

Monit: Der Wachhund für deinen Server

Man kann seinen favorisierten Terminalemulator anwerfen, Screen starten und darin dann nützliche Applikationen für die Konsole ausführen, die jedes Detail des eigenen Rechners auf Schritt und Tritt überwachen. Die Methode verliert jedoch ihren Reiz, sobald man schlafen muss oder mehr als nur eine Handvoll Daten im Blick behalten möchte.
Um meinen Server zu überwachen benutze ich zur Zeit Munin und Monit, die sich gegenseitig sehr gut ergänzen. Ersterer überwacht alle wichtigen Aspekte des Systems wie Systemlast, Speicherverbrauch, Festplattenbelegung, Traffic, ja sogar die Anzahl der Spieler und kann all das mit Hilfe von Graphen anschaulich visualisieren, wodurch sich Trends frühzeitig erkennen lassen. Monit hingegen ist ideal dafür geeignet um Prozesse zu überwachen, diese gegebenenfalls neuzustarten und beim Erreichen kritischer Schwellwerte Alarm per E-Mail-Benachrichtigung auszulösen.
In diesem Beitrag beschreibe ich in Kürze, was Monit auf meinem Spieleserver mit Debian für Aufgaben hat und wie man ihn unkompliziert einrichtet.

Installation

aptitude install monit

Damit Monit bei jedem Neustart automatisch gestartet wird, muss folgende Variable in /etc/default/monit gesetzt sein.

startup=1

Konfiguration

Die zentrale Konfigurationsdatei von Monit liegt in /etc/monit/monitrc und ist genauso wie das Handbuch, man monit, ausgezeichnet dokumentiert. Die offizielle Dokumentation ist ausführlich und mit vielen Beispielen gespickt.

set daemon 120
Überprüft die Dienste alle 120 Sekunden.
set logfile syslog facility log_daemon
Alle Nachrichten werden nach syslog vom Benutzer Munin geloggt. Hier könnte auch der volle Pfad zu einer separaten Logdatei stehen.
set idfile /var/.monit.id
Der Ort, wo die einzigartige ID der Monitinstanz gespeichert wird
set statefile /var/.monit.state
Diese Datei speichert den aktuellen Zustand der überwachten Prozesse, welcher durch die persistente Speicherung auch nach einem Neustart von Monit wiedererkannt wird.
set mailserver localhost
Hier wird ggf. ein Backupserver und externer Mailserver eingetragen. Ich habe mir einen eigenen aufgesetzt.
set alert root@localhost
Die E-Mail-Adresse, welche in einem Problemfall alarmiert werden soll.

Allgemeine Systemressourcen

Hier werden Systemlast, Speicherauslastung und CPU-Beanspruchung überprüft. Die Syntax ist sehr übersichtlich und selbsterklärend. Wenn ein Wert einen Schwellwert überschreitet soll alarmiert werden.

check system localhost
if loadavg (1min) > 2 then alert
if loadavg (5min) > 1 then alert
if memory usage > 75% then alert
if cpu usage (user) > 70% then alert
if cpu usage (system) > 45% then alert
if cpu usage (wait) > 45% then alert

Prozesse überwachen

Die meisten Einträge sehen bei mir wie der untere aus. Der OpenArena-Server wird automatisch neugestartet, wenn der Verfügbarkeitstest auf Port 27960 mit dem UDP-Protokoll fehlschlägt. Der Konfigurationsblock lässt sich leicht auf Dienste wie SSH, Lighttpd oder Exim übertragen. Sollte der Prozess fünf Mal innerhalb von fünf Zyklen neugestartet worden sein, soll Monit die Versuche einstellen.

check process openarena-server with pidfile /var/run/openarena-server.pid
start program = "/etc/init.d/oa_ded start"
stop program = "/etc/init.d/oa_ded stop"
if failed host 134.0.24.218 port 27960 type udp then restart
if 5 restarts within 5 cycles then timeout
alert root@localhost but not on { instance pid }

Möchte man nur über bestimmte Warnmeldungen per Mail informiert werden, hilft die Konstruktion alert but not on weiter.

Apache Webserver

Das Beispiel stammt direkt aus der monitrc und verdeutlicht noch einmal wie logisch die Konfiguration aufgebaut ist. Monit ist z.B in der Lage pro Prozess die CPU-Auslastung zu überwachen und bei 60% zu alarmieren und dann bei 80% den Webserver neuzustarten und bestehende Verbindungen somit zu trennen. Des Weiteren lässt sich das auch auf den Speicherverbrauch und Kindprozesse anwenden.

check process apache with pidfile /usr/local/apache/logs/httpd.pid
start program = "/etc/init.d/httpd start" with timeout 60 seconds
stop program = "/etc/init.d/httpd stop"
if cpu > 60% for 2 cycles then alert
if cpu > 80% for 5 cycles then restart
if totalmem > 200.0 MB for 5 cycles then restart
if children > 250 then restart
if loadavg(5min) greater than 10 for 8 cycles then stop

Dateitests

Besonders nützlich sind auch Dateitests. Zum einen ist es ein Sicherheitswerkzeug. Geänderte Dateiberechtigungen an wichtigen Systemdateien können sofort erkannt werden, ein veralteter Zeitstempel könnte auf ein Problem mit einem Dienst hindeuten. Außerdem kann die Dateigröße überwacht und z.B. ein Skript ausgeführt werden, welches die Datei an einen anderen Ort verschiebt.

check file openarenalog with path /home/openarena/.openarena/baseoa/games.log
if failed permission 700 then alert
if failed uid openarena then alert
if failed gid openarena then alert
if timestamp > 15 minutes then alert
if size > 100 MB then exec "/usr/local/bin/meinskript.sh" as uid openarena and gid openarena

Monit im Browser anschauen

set httpd port 2812 and
allow admin:monit

Monit bringt einen eigenen Webserver mit, der auf Port 2812 die überwachten Prozesse übersichtlich darstellt. Dabei ist es möglich diese Dienste im Webinterface neuzustarten oder Monit anzuweisen die Überwachung kurzfristig auszusetzen. Den Port muss man mit der Firewall nicht freigeben. Man kann z.B einen SSH-Tunnel zum Betrachten nutzen und dann mit http://localhost:2812 im eigenen Browser als Benutzer admin mit dem Passwort monit sich das Ganze ansehen. Z.B.
ssh -p 44443 -L 2812:deinserver:2812 user@deinserver

Fazit

Monit ist leicht zu installieren und ebenso leicht zu konfigurieren. Ist das einmal erledigt verrichtet er unaufdringlich im Hintergrund seine Arbeit und schlägt sofort an, wenn ein Grenzwert überschritten wurde. Ich vermisste an der Version in Debian Squeeze nur die Möglichkeit die Überwachung auch mal für einen kurzen Zeitraum zu unterbinden, wenn z.B ein Backup gemacht wird und deswegen einige Werte kurzzeitig überschritten werden. Die Funktion ist in Wheezy aber vorhanden und findet sich unter "Service Poll Time".

Opfer und Täter zugleich: Wenn der Spieleserver für eine DoS-Attacke missbraucht wird

Behauptete ich an irgendeiner Stelle, dass das mit dem Spieleserver ein kleines Projekt werden solle, dem nicht viel Zeit gewidmet würde? Ich muss im Delirium gewesen sein. Zugegebenerweise es geschieht nicht jeden Tag, dass ich plötzlich entdecke, dass mein OpenArena-Server als Verstärker und Waffe in einer DoS-Attacke auf Webserver und andere unbescholtene Dienste im Internet dient.
Als ich am Samstag auf meinem Server einloggte um ein paar Webseiten von linuxiuvat.de anzupassen, wollte ich kurz den monatlichen Traffic-Verbrauch überprüfen. Ein nützliches Werkzeug dafür ist z.B. slurm, das ich letzten Sommer mal mit meinen anderen favorisierten Systemmonitoren für die Konsole vorgestellt habe. Slurm zeigt übersichtlich den ein- und ausgehenden Netzwerkverkehr in Echtzeit an, konzentriert sich dabei aber nur auf das Wesentliche. Eine detaillierte Aufschlüsselung des Traffic lässt sich mit iftop darstellen, was sich kurz danach noch als nützlich erweisen sollte.
Zu meiner Überraschung signalisierte slurm, dass mein ausgehender Traffic bei 2-3 MB/s lag. Ok, hier werden die Systemadministratoren von Ex-Megaupload sicher schmunzeln, für meinen kleinen vServer war das aber schon eine ganze Menge.
Nur zum Vergleich: Ich habe 1000 GB Traffic frei im Monat, danach wird die Anbindung von 100 Mbit auf 10 Mbit gedrosselt. Momentan liegt mein monatlicher Verbrauch bei ca. 20 GB, obwohl ich vier Spieleserver und einen Webserver online habe. Da ist also noch etwas Luft nach oben...

Netzwerkanalyse

Fasziniert starrte ich also auf slurm und konnte mir über diese Zahl keinen richtigen Reim machen, weswegen ich mir mit iftop die Sache genauer anschaute.


Interessanterweise zeigte sich hier, dass von Port 27960 viel Netzwerkverkehr in Richtung mehrerer Webserver ging, die allesamt keine wirkliche Beziehung zu meinem OpenArena-Server hatten, der auf Port 27960 lauschte. Mit Hilfe von tcpdump konnte ich herausfinden, dass eine Unmenge von getstatus-Kommandos an den OpenArena-Server gesendet wurden, der daraufhin anstandslos Servervariablen und die Anzahl der Spieler an den Webserver übermittelte, womit dieser natürlich gar nichts anfangen konnte. Eine gute Einführung zu tcpdump gibt es im Wiki von ubuntuusers.de.
tcpdump -i eth0 udp and port 27960 -w traffic.log
Mit diesem Befehl lassen sich sämtliche UDP-Pakete, die von und zu Port 27960 geschickt werden "mitschneiden". Ein grafisches Netzwerkanalyse-Werkzeug wie Wireshark, kann später bei der Analyse der Daten helfen.


Wie diese Variablen für meinen Server aussehen, lässt sich z.B. auf der Statusseite von dpmaster.deathmask.net nachschauen.

Nachforschungen

Nach kurzer Recherche im Internet fand ich schon mehrere Beiträge, die ähnliche Probleme beklagten. So zum Beispiel im OpenArena-Forum, bei ioquake.org und im Forum von UrbanTerror. Allen war gemein, dass es sich hier immer um auf Quake3 basierende Spiele handelte.
Hier fiel dann auch das Stichwort: DRDoS-Attacke, was für Distributed-Reflected-Denial-of-Service-Attacke steht. Dabei wurde meinem OpenArena-Server eine falsche Absenderadresse mitgeteilt (IP-Spoofing), so dass dieser die normalerweise harmlose getstatus-Abfrage an einen Webserver leitete. Durch die hohe Anzahl von Anfragen und die relativ großen Pakete, die verschickt wurden, entstand ein Verstärkungseffekt, der noch größer ausgefallen wäre, wenn ich mehrere verwundbare OpenArena-Server installiert gehabt hätte.
Die Täuschung beschränkte sich aber nicht nur auf einen Webserver, sondern gleich auf mehrere, was den Traffic natürlich in die Höhe schnellen ließ. Ich schrieb daraufhin einen Fehlerbericht für Debian mit der Nummer #665656. Innerhalb kürzester Zeit konnte der Paketbetreuer für OpenArena einen Patch einspielen, der die getstatus-Anfragen an den Server begrenzt. Eine Sicherheitsankündigung gab es hierzu auch schon.

Fazit

Ich war ehrlich gesagt überrascht, dass ich derjenige war, der diesen Fehler schließlich an Debian gemeldet hat, obwohl es den Anschein hatte, dass einige vor mir Betroffene auch Debian benutzen. Der Paketbetreuer reagierte sehr schnell und ich denke durch den Fehlerbericht und die Sicherheitsankündigung ist das Problem prominent sichtbar gemacht worden. Der Bug betraf nicht nur OpenArena, sondern praktisch alle Spiele, die eine ungepatchte Quake3-Engine benutzen, so z.B. auch Tremulous.
Ich hatte vor kurzem notwendige Firewallregeln für den Spieleserver vorgestellt, die auch in dieser Form berechtigt sind. Um den Server aber gegen solche DRDoS-Angriffe abzusichern, braucht man auch hinreichende Regeln, die am besten automatisch und dynamisch hinzugefügt werden. Trafficbegrenzung per IP fällt mir hier als Stichwort neben fwlogwatch ein, dass ich schon einsetze.
Insgesamt gibt es gerade zur Netzwerkprotokollierung und -überwachung noch eine Menge zu lernen. Das Ganze soll nicht darüber hinwegtäuschen, dass bisher alles andere wunderbar funktioniert hat und das Projekt wirklich Spass macht. Auf der anderen Seite ist man aber auch dafür verantwortlich, dass der Server nicht Amok läuft und für finstere Zwecke missbraucht wird. Denial-of-Service-Attacken fallen in Deutschland unter Computersabotage und können mit bis zu drei Jahren Freiheitsstrafe geahndet werden. Ich hoffe der Richter lässt in diesem Fall Milde walten. 😉

Nur versenden: Mailserver mit Debian und Exim

SSH-Zugang ist gesichert, Firewall ist aktiv, Zeit für den ersten Spieleserver. Noch nicht ganz. Irgendwie muss man informiert werden, wenn es auf dem eigenen vServer brennt und Grenzwerte überschritten werden. Später wird Cron täglich Infomails verschicken und eventuell möchte man seinen Besuchern die Möglichkeit bieten mit den Webanwendungen zu interagieren. Für all diese Szenarien braucht man einen Mailserver.
Die folgende Anleitung beschreibt die Einrichtung des leichtgewichtigen Mailservers Exim4 mit Debian Squeeze. Der Server dient einzig und allein dazu Mails zu versenden. Ich brauchte keine vollständige Mailserverlösung und wollte schnell produktiv sein. Ich bin dennoch über admin [at] linuxiuvat [de] erreichbar, indem ich den MX Resource Record über das Webinterface meines VPS-Anbieters geändert habe und zu einem externen Mailprovider verweise.

Empfehlenswerte Links

MTA Comparison
Send-only Mail Server with Exim (Linode Library)

Installation

aptitude install exim4-daemon-light

Konfiguration

dpkg-reconfigure exim4-config
1. Wir haben einen Internetserver und versenden Mails über SMTP

2. Hier muss der vollqualifizierte Domänenname (FQDN) des Rechners eingetragen werden. Dieser lässt sich in der Datei /etc/hostname festlegen und war bei meinem Anbieter schon voreingestellt.

3. Wir nehmen keine externen Verbindungen an und leiten Mails nur von lokalen Diensten weiter. Deswegen 127.0.0.1

4. Hier steht wieder nur unser FQDN

5. Wir leiten keine Mails weiter. Der Server dient nicht als Relay. Deswegen einfach leer lassen.

6. Das System dient auch nicht als Sendezentrale (Smarthost). Deswegen bleibt auch hier alles leer.

7. Der vServer ist permanent an das Internet angebunden. Deswegen muss diese Abfrage mit Nein beantwortet werden.

8. Die Wahl zwischen Mbox und Maildir. Zwei Formate, die beim Zustellen lokaler Mails auf dem Rechner verwendet werden. Debian empfiehlt Mbox. Ich habe das Maildir-Format gewählt und bis dato keine Probleme gehabt.

9. Die Einstellungen lassen sich auf eine große oder mehrere kleine Dateien aufteilen. Geschmackssache. Ich habe die große Datei gewählt.

Als letzten Schritt wird man gefragt an welche lokalen Benutzer E-Mails weitergeleitet werden sollen. Hier habe ich Root und eine externe Mailadresse gewählt. Die Einstellungen lassen sich auch später noch in /etc/aliases ändern.
Das war es auch schon. Der Mailserver ist danach einsatzbereit, nimmt ausschließlich nur lokale Mails entgegen und leitet sie an Root und die externe Mailadresse weiter. Testen lässt sich der Mailserver mit:
echo "Hallo Welt. Das ist ein Test" | mail -s Testmail email@example.com

Debian-Server mit der unkomplizierten Firewall ufw absichern

Zwischen dem Sperren des Root-Zugangs für SSH und dem Installieren des ersten Spieleservers musste ich eine Firewall einrichten. Ich bin noch kein Firewall-Experte, weswegen ihr genau überlegen solltet, ob die folgende Anleitung euren Ansprüchen genügt. Fakt ist aber, dass ich damit momentan meinen Spieleserver mit Debian schütze und ich damit bisher zufrieden sein kann. 😉
Die Errichtung einer Barriere mit Hilfe von netfilter und iptables unterstützen heute viele Werkzeuge. Ich hatte mir ufw und arno-iptables-firewall als mögliche Kandidaten ausgesucht und mich dann für die "unkomplizierte Firewall" entschieden.
Ursprünglich von Ubuntu entwickelt bietet ufw eine einfache Möglichkeit nur die Dienste freizugeben, die tatsächlich öffentlich verfügbar sein sollen.

Installation

aptitude install ufw

Konfiguration

ufw enable


Aktiviert die Firewall. Bestehende SSH-Verbindungen können unter Umständen getrennt werden. Standardmäßig werden eingehende Verbindungen geblockt und ausgehende Verbindungen erlaubt. Bevor man die Firewall aktiviert, kann man z.B. mit

ufw allow proto tcp from any to any port 22


explizit Port 22 für den SSH-Zugang freigeben.

ufw allow 44443/tcp


In der vergangenen Erklärung konnte man sich über Port 44443 per SSH einloggen, also muss zuerst dieser Port mit allow freigeschaltet werden. Dabei lässt sich mit /udp oder /tcp die Erlaubnis auf bestimmte Protokolle eingrenzen oder ohne auf beide ausdehnen.

ufw limit 44443/tcp


Noch mehr Sicherheit bietet die Limit-Funktion von ufw, mit der die Anzahl von eingehenden Verbindungen pro IP begrenzt wird, wodurch Brute-Force-Attacken deutlich erschwert werden.

ufw default deny


Im Prinzip der wichtigste Schritt, da dadurch standardmäßig alle eingehenden Verbindungen abgewiesen werden. (Genauer, jedes eingehende Packet wird kommentarlos verworfen. DROP)

ufw status verbose


Zeigt den Status der Firewall an. Oder einfach nur ufw status.

ufw allow 27960/udp


Gibt den UDP Port 27960 für OpenArena frei.

ufw allow 40000:40009/udp


Gibt die Ports von 40000 bis 40009 für UDP frei (XPilot-ng)

ufw allow http


Eine andere Schreibweise um Standard-Port 80 für den Webserver freizugeben

ufw logging on und ufw logging medium


Der erste Befehl schaltet die Logfunktion der Firewall ein (standardmäßig auf niedrig). Weiterhin gibt es noch medium, high und full.

ufw delete allow 44443/tcp


Mit der Delete-Funktion lassen sich Regeln im laufenden Betrieb auch wieder löschen.

Ausgehende Verbindungen

Ausgehende Verbindungen werden standardmäßig erlaubt. Im meinem Fall bin ich der einzige Benutzer mit Shellzugriff auf meinem Server und es gibt bisher weder CGI noch PHP-Anwendungen, die man manipulieren könnte um diese Einstellung zu missbrauchen. An dieser Stelle scheiden sich die Geister. Tatsache ist, man kann sein System so fest zuschnüren, dass nicht einmal ausgehende Verbindungen erlaubt sind oder einen Mittelweg finden.

ufw deny out to any


Blockiert alle ausgehenden Verbindungen

ufw allow out 80,443/tcp


Erlaubt ausgehende TCP-Verbindungen für Port 80 und 443.

IPv6

UFW blockt standardmäßig alle Anfragen mit IPv6. Damit ufw mit IPv6 zusammenarbeitet muss in /etc/default/ufw die Variable IPV6 auf Yes gesetzt und die Firewall einmal mit ufw reload neu gestartet werden.

Fazit

Die unkomplizierte Firewall macht ihrem Namen alle Ehre. Das Prinzip ist immer das gleiche. Alle eingehenden Verbindungen verwerfen und nur die tatsächlichen Dienste freigeben, die man wirklich braucht. Wie restriktiv man ausgehende Verbindungen behandelt, hängt vom eigenen Benutzerszenario ab. Die Regeln lassen sich noch deutlich verfeinern. Mehr Informationen verrät man ufw oder die folgenden Links.

Links

Ubuntu ufw Documentation
Firewall Ubuntu Servers

SSH-Schlüssel, Port ändern und Anmeldung als Root verwehren

Nachdem mir meine Zugangsdaten zum vServer übergeben worden waren, war meine erste Aktion mit dem neuen SpielArbeitsgerät den SSH-Zugang abzusichern. Die folgende Anleitung zeigt in Kürze, wie man verhindert, dass Root sich per SSH anmelden darf, SSH auf einem anderen Port lauscht und eine Anmeldung nur noch mit einem gültigen SSH-Schlüssel möglich ist und das Einloggen per Passworteingabe deaktiviert wird.
Diese Prozedur ist bei jedem öffentlich zugänglichen Server sinnvoll, wie ein Vorfall letzte Woche wieder einmal gezeigt hat. In einer größeren Institution wurde ein Server kompromittiert, bei dem sich der Angreifer mit Hilfe einer Wörterbuch-Attacke direkt Rootzugriff über SSH verschaffen konnte, indem er innerhalb weniger Stunden ca. 40.000 Passwörter ausprobieren durfte. Software wie denyhosts, fail2ban oder eine Firewalleinstellung, die nur Zugriff aus "vertrauenswürdigen" Netzen erlaubt und natürlich ein stärkeres Passwort, wäre hier eine Möglichkeit gewesen den Einbruch zu verhindern.
Mein kleines Projekt bietet mir die einfache Möglichkeit auf noch mehr Sicherheit, da außer mir selbst niemand Shellzugriff benötigt und nichts dagegen spricht den berechenbaren Namen des Root-Zugangs zu deaktivieren und nur noch die Authentifizierung per SSH-Public-Key-Verfahren zu erlauben. Bevor das geschieht, muss man natürlich einen weiteren, unprivilegierten Benutzer mit adduser hinzufügen.

Schlüsselerzeugung

ssh-keygen

Ohne weitere Argumente erstellt dieser Befehl einen privaten und öffentlichen RSA-Schlüssel für die SSH-Protokollversion 2 auf dem lokalen Rechner. Bejaht man alle folgenden Fragen, wird das Schlüsselpaar in ~/.ssh/ gespeichert. Ebenso wird man nach einem Passwort gefragt, um den privaten Schlüssel später entsperren zu können. Ich empfehle eines zu setzen, auch wenn man dadurch einmal pro Sitzung das Passwort eingeben muss.

Öffentlichen Schlüssel auf den Server transferieren

ssh-copy-id user@euervps123.de

Der öffentliche RSA-Schlüssel befindet sich danach auf eurem Server in ~/.ssh.

Einloggen

Funktioniert wie bisher,

ssh user@euervps123.de

nur dass ihr jetzt das Passwort zum Entsperren des privaten Schlüssels auf eurem Rechner eingeben müsst. Die Rechte der privaten Schlüsseldatei id_rsa müssen restriktiv sein.

chmod 600 ~/.ssh/id_rsa

Schlüssel ohne Eingabe des Passworts benutzen

Unter Gnome 3 genügte bei mir

ssh-add

auszuführen, um den privaten Schlüssel dem Authentifizierungsagenten, ssh-agent, hinzuzufügen, der hier durch die Anwendung gnome-keyring bereitgestellt wird. Nach einmaliger Eingabe des Passwortschutzes für den privaten Schlüssel ist dieser die gesamte Sitzung ohne weitere Passwortabfrage benutzbar.
Arbeitet ihr ohne X auf der Konsole müsst ihr zuerst den

ssh-agent zsh


mit eurer bevorzugten Shell aufrufen und könnt danach den privaten Schlüssel wieder wie oben beschrieben mit ssh-add für die Sitzung dauerhaft entsperren.

Root-Zugang deaktivieren, Port verändern und Passwort-Authentifizierung abschalten

Hierzu muss die Datei /etc/ssh/sshd_config auf dem Server angepasst werden.
Wichtig! Bevor ihr die Veränderung vornehmt, solltet ihr absolut sicher sein, dass ihr euch mit dem neu generierten Schlüssel anmelden könnt. Ebenso müsst ihr unbedingt die Einstellungen der Firewall so anpassen, dass ein Anmelden über den neuen SSH-Port erlaubt ist. (siehe nächster Beitrag).
Folgende Optionen werden geändert:

Port 44443
PermitRootLogin no
RSAAuthentication yes
PubkeyAuthentication yes
PasswordAuthentication no
X11Forwarding no

Fazit

Der Port kann im Prinzip beliebig gewählt werden. Die Liste der standardisierten Ports hilft bei der Entscheidung. Der Wechsel von Port 22 auf z.B. Port 44443 lässt die Mehrzahl automatischer Programme ins Leere laufen, die nur überprüfen, ob auf dem Standardport ein SSH-Dienst angeboten wird. Anmelden kann man sich ab sofort mit

ssh -p 44443 user@euervps123.de


Das Abschalten der Passwort-Authentifizierung macht Wörterbuch-Attacken aussichtslos. Das Deaktivieren des Root-Logins erzwingt die Anmeldung mit einem unprivilegierten Benutzer, so dass ein Angreifer nicht nur die Hürde des SSH-Schlüssels überwinden, sondern noch ein weiteres Passwort in Erfahrung bringen muss.
Sicherheit ist ein Prozess, heißt es so schön. Für mein spezielles Benutzerszenario funktioniert dieser Weg. Fehlerhaft konfigurierte Dienste und Sicherheitslücken kann aber auch diese Anleitung nicht verhindern.

Links

https://help.ubuntu.com/community/SSH/OpenSSH/Configuring
http://bodhizazen.net/Tutorials/SSH_keys
Sicherer Datentausch: Ein sftp-Server mit chroot

Transmission-remote-cli womöglich schon bald offiziell in Debian

Im Januar widmete ich mich der Bittorrent-Anwendung Transmission und seinen Begleitern für die Konsole, allen voran transmission-remote-cli. Der in Python geschriebene Konsolenklient kann mit Hilfe von Ncurses alle Aufgaben des grafischen GTK/QT Clients übernehmen, kommt dabei aber vollkommen ohne grafischen Ballast aus und ist dementsprechend ressourcenschonender für ältere Rechner oder effizienzbewusste Serveradministratoren. Mit einem Augenzwinkern wünschte ich mir schon damals ein eigenständiges Debian-Paket.
Seit heute zeichnet sich ab, dass meine Wünsche Realität zu werden scheinen, denn Fehlerbericht Nummer #663017 wurde verfasst, der sich mit der Bitte um Aufnahme in Debian beschäftigt. Mit etwas Glück gibt es also schon bald ein eigenständiges Debian-Paket, welches eine echte Alternative zum Champion der Bittorrent-Klienten für die Konsole sein kann: rtorrent.

Webseiten aufräumen mit Tidy

Eine von WordPress Stärken ist die einfache Einrichtung und die Vielzahl an vorgefertigten Themen und Möglichkeiten dieses Content Management System zu erweitern. Der Nachteil ist die relativ hohe Belastung von Serverressourcen und teils überflüssiger HTML-Code, der durch das Backend erzeugt wird.
Für mein neues Projekt brauchte ich eine ressourcenschonendere Lösung und da ich den Inhalt nur einmal schreiben musste, war die Lösung klar: statische Seiten mit XHTML Strict 1.0, CSS und der händischen Methode.
Nachdem man das Markup als Grundgerüst erstellt hat, muss man sich in der Regel nur noch um das Layout mit CSS kümmern, wo ich mich von der vor kurzem entdeckten Homepage von Jozu-kun habe inspirieren lassen. Das Design ist schlicht, 100 % standardkonform und effizient. Mir hat es auf Anhieb gefallen.

Leider ist man beim Tippeln mit Vim nicht vor Fehlern gefeit. Sonderzeichen müssen in HTML-spezifischen Code umgewandelt werden. Die händische Methode kam da schon gar nicht in Frage, wenn schon hätte es eine Vim-Funktion oder Plugin sein sollen.
Warum nicht Tidy dafür nehmen? Mit Tidy hat das World Wide Web Konsortium ein Programm geschaffen, dass automatisch HTML-Code auf Fehler überprüft und durch sauberen, standardkonformen Code ersetzen kann. Ein paar Beispiele, was Tidy genau korrigiert finden sich bei w3.org. Für meine XHTML Seiten, die in UTF-8 kodiert sein sollten, benötigte ich lediglich diesen simplen Befehl und die schon automatisch im Debian-Paket verfügbaren Konfigurationsdatei /etc/tidy.conf um z.B. die Datei index.html "zu säubern".

tidy -m index.html

output-xhtml: yes
add-xml-decl: no
doctype: strict
char-encoding: utf8
indent: auto
wrap: 76
repeated-attributes: keep-last
error-file: errs.txt

Das Dokument wurde dann nicht nur validiert und auf Fehler korrigiert, sondern auch Einrückungen, Zeichenkodierung und Umbrüche vorgenommen. Einfacher ging es nicht. Wie das vorläufige Ergebnis aussieht, dazu demnächst mehr.