Posts mit dem Label server werden angezeigt. Alle Posts anzeigen
Posts mit dem Label server werden angezeigt. Alle Posts anzeigen

Sonntag, 31. Juli 2011

postfix: IP-Adresse des Absenders verbergen

Nach langer Zeit gibt es heute mal wieder einen kleinen Post aus der Sysadmin-Ecke.

Die Ausgangslage

Ein Benutzer liefert seine Emails mit Authentifizierung bei einem durch mich betriebenen Mailserver ein, der für die entsprechende Domain zuständig ist.

In den Headern dieser Mail wird nun die IP-Adresse auftauchen, von der aus die Email eingeliefert wurde. Dies kann die IP zu Hause sein, die von einem Bekannten oder die von einer Institution. Postet derjenige häufiger auf Mailinglisten kann man so schon ein Profil erstellen und bekommt auf jeden Fall heraus, dass er z.B. Emails von der Uni aus sendet, etc.

Dies möchte man nun verhindern - und das funktioniert mit postfix Bordmitteln sogar relativ einfach.

Mehr Information ist am Ende doch weniger

Zunächt müssen wir die entsprechenden Header erkennen können. Da bei allen nicht-authentifizierten Emails die IP-Adresse des einliefernden MTA im Header unverändert erhalten bleiben soll, schon um Spammer identifizieren zu können ohne extra in die Logs schauen zu müssen, brauchen wir einen Weg, die passenden Received:-Header zu erkennen. Dies erreichen wir, indem wir dem postfix sagen, dass er den Benutzernamen des Absenders auf dem Mailserver in den Header einfügen soll. Dies geschieht über die Anweisung smtpd_sasl_authenticated_header = yes in der Datei main.cf des postfix.

Unser header sieht nun ungefähr so aus:

Received: from [192.168.101.150] (guest123.guest.example.org [192.0.43.10])
  (using TLSv1 with cipher DHE-RSA-CAMELLIA256-SHA (256/256 bits))
 (No client certificate requested)
 (Authenticated sender: username)
 by mail.somedomain.tld (Postfix) with ESMTPSA id 32A59B1C032
 for ; Thu, 30 Jun 2011 12:36:07 +0200 (CEST)

Die hervorgehobene Zeile ist neu hinzugekommen und ermöglicht es uns im zweiten Schritt nach genau diesen Headern zu suchen.

pcre ftw!

postfix bietet dafür die Möglichkeit der header_checks. Damit kann man mittels (perl) regular expressions auf den Headern der Email arbeiten und Zeilen einfügen, Zeilen ändern und eigentlich vor allem Aktionen auslösen wie das Aufhalten einer Email, Abweisen, Weiterleiten, etc.

Wir benutzen diese Möglichkeiten, um auf der oben gezeigten Received:-Zeile ein paar Ersetzungen vorzunehmen.

Dazu stellen wir zunächst sicher, dass die main.cf des Postfix auch header checks aktiviert hat:

 smtpd_sasl_authenticated_header = yes
 ...
 header_checks      =  pcre:/etc/postfix/header_checks
 mime_header_checks =  pcre:/etc/postfix/header_checks

Nun koennen wir in der angegebenen Datei header_checks mit folgender Zeile das Umschreiben aktivieren:

/^Received:\ from (.*)\(.*\)(.*)\(Authenticated\ sender:\ .*\)(.*by mail\.somedomain\.tld.*)$/U  REPLACE Received: from $1 (Remote IP hidden) $2(Sender was authenticated on somedomain.tld) $3

Hinweis: Die Zeile ist relativ lang, beim Kopieren aufpassen sie komplett zu erwischen. Wichtig ist die Option U an der Regex, diese schaltet sie auf ungreedy. Siehe man pcre_table.

Der Name des Mailservers taucht hier nochmal auf, damit ich die Original-IP bei extern eingelieferten Emails nicht verwerfe - das kann zum Identifizieren von Spammern helfen, auch wenn die Header oft gefälscht sind.

Im Ergebnis sieht der Header der Email nun aus wie folgt:

Received: from [192.168.101.150]  (Remote IP hidden) 
 (using TLSv1 with cipher DHE-RSA-CAMELLIA256-SHA (256/256 bits))
 (No client certificate requested)
 (Sender was authenticated at somedomain.tld) 
 by mail.somedomain.tld (Postfix) with ESMTPSA id A36241184685
 for ; Fri, 29 Jul 2011 20:23:31 +0200 (CEST)

Wenn man die private IP auch noch entfernen möchte, kann man sich jetzt natürlich einen weiteren Header-check überlegen, der auf '\[.*\].*Remote IP hidden' triggert und diese ersetzt. Das kann im Einzelfall notwendig werden, wenn kaputte Antispam-Maßnahmen anderer Empfänger solche Emails ablehnen.

Wenn man misstrauisch ist fügt man ausserdem noch eine Zeile hinzu, die jedes Vorkommen von '(Authenticated sender: ...)' mit etwas belanglosem ersetzt, falls man unter allen Umständen die internen Nutzernamen geheim halten will.

Sonntag, 28. November 2010

Server mit Migrationshintergrund

Dieser Post soll allen als Warnung dienen, die einen Rootserver gemietet haben. Es kann einem passieren, dass der Provider beschließt, daß die alte Hardware zuviel Strom frisst, und er die Server der Kunden virtualisieren möchte.

Zustimmung des Kunden

Ein normaler Provider würde dann einen Brief schreiben. Oder vielleicht auch eine Email. Dann auf Antwort warten, und wenn der Kunde sein OK gibt und vielleicht noch einen Terminwunsch äussern darf (nicht während der Produktpräsentation z.B.) wird die Migration durchgeführt oder auch nicht.

Alles andere ist eine einseitige Vertragsänderung die unmittelbar Sonderkündigungsrecht des Kunden zur Folge hat.

Handeln ohne Zustimmung?

Bei einem meiner Provider war das leider nicht so. Ich erhielt eine Email, in der man die neue Virtualisierungslösung anpries und dass man wegen Erneuerung von Hardware meinen Server gerne migrieren würde. Das ist für mich Konjunktiv.

Das Problem war nur, dass ich diese Email eine Woche lang nicht zur Kenntnis genommen habe, weil Thunderbird der Meinung war, sie nicht anzeigen zu müssen. Alles halb so schlimm, könnte man meinen, die Nachricht war ja im Konjunktiv, und kein vernünftiger Provider würde einen Kundenserver nehmen, runterfahren, die Festplatte ausbauen, die Daten kopieren, auf ein Storage mit den Daten aller anderen Kunden legen...

Nun, genau das hat dieser Provider aber getan. Er hat nicht auf eine Antwort gewartet und einfach mal so die Festplatte ausgebaut und in einer Stunde Downtime die Daten kopiert.

Gemerkt habe ich es, weil Nagios gemeckert hat, dass der Server down ist.

Als ich nach etwas Suchen dann feststellte, dass mir Thunderbird Mails unterschlägt, fand ich nach einem Index-Rebuild auch die Email, die auf diese Migration "hinwies", bzw. mich eigentlich darauf hinwies, dass man das gerne tun würde, dieses Migrieren

Was ist 'Ausspähen von Daten'?

Auf meine Email hin, dass ich hier einen Fall von "Ausspähen von Daten" sehe und nicht damit einverstanden bin, dass man einfach meine Daten kopiert, erhielt ich dann gegen 16:09 eine Email, in der man mich fragt, ob ich mit einer Rückmigration auf die alte Hardware einverstanden sei. Diesmal war das sogar als Frage formuliert!

Lernresistent? Könnte man meinen.

Ja, nur leider sehe ich im Syslog, dass der Server um 17:05 und 17:10 rebootet. Es wurde wieder keine Antwort abgewartet - diesmal nicht mal eine Stunde lang - und es wurde erneut ohne Absprache mit den Daten hantiert. Die gehosteten Webseiten waren damit mal wieder nicht erreichbar. Und der Nameserver und Mailserver auf der Kiste auch nicht.

Dieser Zustand wurde leider auch 3 Stunden lang nicht besser. Obwohl ssh irgendwann wieder ging. Des Rätsels Lösung: Sie haben beim Rückmigrieren das Routing verbockt. Nach einer Email an die Notfall-Hotline war das aber dann wenigstens in Rekordzeit behoben - unter 10 Minuten.

got root?

Ich habe nach diesem Vorfall unmittelbar einen anderen Hoster gesucht.

Der neue Server war schließlich am Mittwoch einsatzbereit, im Verlauf des Tages habe ich dann einiges an Domains umziehen dürfen, darunter diverse CMS-Systeme, den Mailserver und den Nameserver für eine zweistellige Zahl an Domains und alle Nutzer und Kunden über die neuen IPs bzw. Nameserver informieren müssen, damit sie ihre DNS-Zonen ggf. anpassen.

finally?

Zwischendurch habe ich dann noch Kontakt zu einem Anwalt aufgenommen, um mir die rechtliche Situation mal ein bisschen genauer darlegen zu lassen.

Nun, die Kündigung beim Provider folgt zum 01.12.2010 - der alte Server ist nun endgültig platt. Genullt. Ob der Provider noch eine Kopie der Daten irgenwo im Backup hat - wer weiss....

Dienstag, 2. November 2010

RANT: Wer darf heutzutage eigentlich Mailserver betreiben?

Mir platzt hier gleich die Hutschnur. Man ist mal eine Woche zum Entspannen (und wegen einer Tagung)) aufs Land gefahren, und dann ist man andauernd am Server fixen. Arrgh.

Ein Drama in drei Akten

Dass einer meiner Server am Sonntag (natürlich während des gemütlichen Abendessens bei der Familie) wegen zu wenig RAM ausstieg ist ja meine Schuld, aber was dann gestern und heute sonst noch passierte muss ich einfach mal loswerden.

1. Akt: Die Uni

Gestern Abend hatte die Uni Probleme. Ausnahmslos alle Emails wurden mit einem permanenten Fehler abgewiesen:

 ...
 host localhost [127.0.0.1]: 
   550-Mailbox unknown. Either there is no mailbox associated with this
   550-name or you do not have authorization to see it.
   550 5.1.1 User unknown

Das ist natürlich genial für Mailinglisten - von denen fliegt man dann in der Regel runter - aber auch, wenn man wie ich bei seinem Hoster diese Adresse angegeben hat (weil unabhängig von den Systemen die man dort hosted) und dann die Rechnung oder Trafficabrechnung einen User unknown rauswirft.

Natürlich war gestern der Monatserste und natürlich hat mein Hoster mir versucht an diesem Tag die Rechnung und die Trafficabrechnung zu schicken. Die Trafficabrechnung ist angekommen. Die Rechnung (noch?) nicht.

2. Akt: Der Ticketversender

Ich bin diese Woche weggefahren, weil ich am Donnerstag zu einer Tagung will. Dazu braucht man natürlich ein Ticket. Und wie bekommt man das? Richtig, über einen Dienstleister. Dazu meldet man sich dort an, bezahlt das Ticket und wartet auf das pdf mit dem Ticket.

Und wartet. Und wartet. Und schreibt eine Email an den Support.

Denn: zum Passwort ändern auf der Plattform muss man eine Email bestätigen, aber die kommt ebenfalls nicht an.

Nun bekam ich dann heute eine html-only Email, dass das Ticket nochmal versendet wurde. Aber es kam nicht an, dafür füllte sich mein Maillog:

postfix/smtp[18334]: connect to mail2.amiando.com[213.183.6.102]:25: Connection refused
postfix/smtpd[18137]: NOQUEUE: reject: RCPT from mail.amiando.com[195.71.125.161]: 
  450 4.1.7 <no-reply@mail.amiando.com>: Sender address rejected: unverified address:
      Address verification in progress; from=<no-reply@mail.amiando.com>
      to=<xxxxx@XXXXXXXXX> proto=ESMTP helo=<lnxp-1930.srv.mediaways.net>

Die HTML-Mail löste bei mir leichte Übelkeitsgefühle aus, aber als ich den Eintrag im maillog auswertete wurde mir irgendwie schlecht.

Diese Leute versenden Emails und wundern sich, dass sie als SPAM erkannt wird?

Fassen wir mal zusammen:

Die Email ist HTML-Only, die Absenderadresse existiert nicht, so dass sie bei Fehlzustellungen nichts davon bemerken - deren System wird es also immer wieder versuchen, an eine nicht-funktionierende Adresse von einer ebenfalls nicht-funktionierenden Adresse aus mails zu versenden. Damit macht man sich bei den postmastern, die diese Bounces bekommen, so richtig beliebt.

Dann meldet sich der Mailserver mit dem Namen lnxp-1930.srv.mediaways.net obwohl er laut DNS eigentlich mail.amiando.com heissen sollte. Noch ein SPAM-Kriterium.

Und zur Kröhnung schreiben sie einen Mailserver in ihre Zone, dessen SMTP-Port Verbindungen ablehnt.

3. Akt: Services die verbinden...

Mit dem Spruch wirbt eine andere Firma für ihre Dienste. Leider scheint es damit nich so weit her zu sein. Ich bekomme hier jedenfalls Emails von der Adresse www-data@int3.web.int.fra.privatnetz.org

Mein Mailserver scheitert dann laut syslog aber daran, wenn er versucht mails an die IP 10.1.1.100 zuzustellen.

Die haben doch allerernstes sowohl hostnamen mit privaten IPs in ihrem DNS, als auch MX-Records die auf private IPs zeigen! Stümper! Das ist 'pollution of the public namespace' was den DNS angeht und auch sonst einfach nur kaputt.

Und dann wundern sich Leute, warum ich NAT und Masquerading hasse!

Das Ergebnis ist dasselbe wie oben: Sie werden niemals Fehlermeldungen erhalten und vielfach als SPAMMER erkannt werden.

Fazit

Ich frage mich langsam echt, ob wir einen Internet-Führerschein brauchen - für Diensteanbieter!

Donnerstag, 4. März 2010

TU-Berlin: Sicherheitswettbewerb der AG-Rechnersicherheit

Die AG-Rechnersicherheit hat parallel zu ihrer Präsenz auf der CeBit einen Wettbewerb gestartet, an dem nun jeder per Internet teilnehmen kann um sein Wissen im Bereich der IT-Security zu testen... Dabei gibt es neben einfachen Fragen auch einige praktische Knobeleien zu lösen. Wer mitmachem möchte, sollte natürlich die Spielregeln lesen und das Anmeldeformular ausfüllen. Ansonsten sei jedem ein Besuch auf der CeBit am Stand B39 in Halle 9 ans Herz gelegt.

Sonntag, 30. August 2009

Webseiten automatisch vor Überlast schützen am Beispiel einer MediaWiki-Seite

Das Szenario: Man ist stolzer Betreiber eines eigenen Servers auf dem ein Wiki läuft. Plötzlich berichtet Heise über das eigene Projekt oder man wird von einer anderen der großen Nachrichten-Portale verlinkt und plötzlich geht auf dem Server gar nichts mehr. Selbst der Zugriff per SSH um zu schauen was los ist funktioniert nicht mehr richtig und alle Nagios-Instanzen schlagen Alarm.

Damit es zu diesem Szenario nicht kommt, gibt es natürlich verschiedene Ansätze. Von redundant vorgehaltenen Servern, die per DNS Round-Robin angesprochen werden, über Loadbalancer auf Routingbasis, etc.

Viele dieser Maßnahmen sind aber entweder recht kostspielig oder haben den Nachteil nicht so gut mit soetwas wie einem Wiki zusammenzuarbeiten.

Es gibt aber eine weitere Möglichkeit, die den Dienst http://coralcdn.org benutzt.

Coral Content Distribution Network

Das Coral Content Distribution Network funktioniert transparent durch das Anhängen einer Domain des Dienstes an eine beliebige Webadresse. So wird aus www.google.de ganz schnell die gecachte Version, wenn man statt dessen www.google.de.nyud.net aufruft.

An dieser Stelle vielen Dank an rbu für den Hinweis auf Coral!

Doch wie kann man diesen Dienst benutzen, um ein Wiki bei Überlast des Servers noch einigermassen erreichbar zu halten?

Ein eigener Host für Coral

Zunächst habe ich zum Testen einen weiteren Virtual Host für das Wiki aufgesetzt, so dass ich dort Einstellungen machen kann, ohne das Wiki unbrauchbar zu machen.

Ausserdem hat das den Vorteil, dass ich https-Zugriffe verhindern bzw. umlenken kann, die über Coral natürlich nicht richtig funktionieren.

Und, noch etwas, dieser Virtual Host soll später vielleicht mal auf einen weiteren Rechner umziehen und kann so noch mehr Last abfedern, indem er statische Dateien wie Bilder direkt aus seinem Cache ausliefert.

Dieser VHost hört auf den originellen Namen cache.meinedomain.tld.

Folgende Parameter wurden (zusätzlich) gesetzt:


      #Dies soll ein Proxy werden, also Zugriff auf
      #folgende Seiten per proxy erlauben:

      <Proxy proxy:http://wiki.meinedomain.tld/ >
            Order deny,allow
            Allow from all
      </Proxy>

      ProxyVia On
      ProxyRequests Off

      #Diese Seite liefern wir auf / aus:
      ProxyPass / http://wiki.meinedomain.tld/
      ProxyPassReverse / http://wiki.meinedomain.tld/

      #Ausserdem Cachen wir auf der Festplatte
      CacheRoot /var/cache/apache2
      CacheDirLevels 2
      CacheDirLength 10
      CacheMinFileSize 10
      CacheMaxFileSize 2000000
      CacheEnable disk /
      CacheEnable disk http://wiki.meinedomain.tld/
      CacheEnable disk proxy:http://wiki.meinedomain.tld/

      #Die Cookies wollen wir nicht mit speichern...
      CacheDefaultExpire 3600
      CacheIgnoreHeaders Set-Cookie

      # Bis hier war das nur die (optionale) proxy-Konfiguration
      # kommen wir nun zum LoadBalancer

      RewriteEngine on
      RewriteCond %{HTTP_USER_AGENT} !^CoralWebPrx
      RewriteCond %{QUERY_STRING} !(^|&)coral-no-serve$
      RewriteMap    lb      prg:/var/www/loadbalance.sh
      RewriteCond   ${lb:%{REQUEST_URI}|NULL} !^NULL
      RewriteRule   ^(.*)$ ${lb:$1|%1}           [P,L]

Der zweite Block definiert ein shellscript als Entscheidungshilfe für das Ziel eines Redirects, wenn der Request nicht von dem coral-webproxy kam. Diese Ausnahme müssen wir konfigurieren, da wir sonst den Coral-Server auf sich selbst umlenken würden.

Und dieses Script ist auch schon das Geheimnis.

Das Redirect-Script

Das folgende Script wird vom apache sofort beim Start geforkt und erhält auf stdin fortan die angefragte URL und kann auf stdout dann ausgeben, wohin denn der Request umgelenkt werden soll.

Damit kann man nun nach eigenem Ermessen Paramter suchen, die für einen Redirect sorgen sollen.

Ich nehme hier das maximum von zweien der Load-Werte, so dass bei zuviel Ansturm die Besucher umgelenkt werden und mit Abflauen des Ansturms (die Besucher bleiben dann ja auf dem Proxy) auch wieder neue Besucherrequests angenommen werden.

Ein wenig zusammengehackt und sicherlich nicht die schnellste Implementierung, aber es erfüllt erstmal seinen Zweck, sollte aber durch ein C-Programm ersetzt werden, welches ein _wenig_ effizienter implementiert ist.

#!/bin/bash

loadbalancer="cache.meinedomain.tld.nyud.net";

while read LINE; do
 load="$(awk '{gsub("\\.",""); if ($1>$2){ print $1} else { print $2 }  }'< /proc/loadavg)"
 if [ "$load" -gt "$(cat /var/www/maxload.conf)" ]; then
   logger -t "loadbalance-cache" "redirecting due to load=$load. request: $LINE"
   printf "http://%s/%s\n" "${loadbalancer}" "${LINE}"
 else
   printf "NULL\n"
 fi
done

In der Datei /var/www/maxload.conf habe ich testweise einfach die Zahl 550 eingetragen, so dass ab einer Load größer 5.5 ein Redirect erfolgt.

Konfiguration des Wikis

Bei Zugriffen über den Proxy muss das Wiki read-only arbeiten. Dafür gibt es mehrere Gründe:

Zum Einen sollen nicht die privaten Previews eines Benutzers gecached werden, zum anderen redirecten wir ja wegen hoher Last - und ein Edit eines Artikels wird sicherlich nicht zum Senken der Last beitragen.

Dazu gibt es einen Codeblock in der LocalSettings.php des Wikis:

if ( preg_match( "/^CoralWebPrx/", $_SERVER['HTTP_USER_AGENT']) > 0
    || preg_match( "/coral-no-serve$/", $_SERVER['QUERY_STRING']) > 0) {

 $wgReadOnly="<span style=\"background-color:yellow;\">Das Wiki ist aus Lastgründen read-only. Du greifst daher gerade über ein Cache auf eine gespeicherte Version zu.</span>";
}

Dadurch verlieren wir zwar auch die PageHits-Zählung im Wiki, aber über einen Proxy werden diese ohnhin nicht mehr korrekt gezählt.

Konfiguration des Wiki-Hosts

Nachdem alles getestet ist und funktioniert, können wir bei Überlast alle Requests auf den Wikiserver direkt auf die cache-Variante von Coral lenken. Dies machen wir mit einigen Zeilen in der Definition des Virtual Hosts:

RewriteEngine on
RewriteMap    lbwiki      prg:/var/www/wiki.meinedomain.tld/loadbalance.sh
Folgende Regeln fügen wir nun an die .htaccess des Wikis an. Das muss geschehen, da wir dort noch andere Rewrite-Regeln definiert haben.
# Alle requests des coral-proxies auf den cache lenken,
# requests von unserem Cache nicht auf unser Cache umlenken.
RewriteCond %{REMOTE_ADDR} !^127.0.0.1$
RewriteCond %{REMOTE_ADDR} !^IP.DES.EIGENEN.PROXIES$
RewriteCond %{HTTP_USER_AGENT} ^CoralWebPrx
RewriteRule   ^(.*)$ http://cache.meinedomain.tld/$1           [R,L]

RewriteCond %{REMOTE_ADDR} !^127.0.0.1$
RewriteCond %{REMOTE_ADDR} !^IP_DES_CACHES$
RewriteCond %{QUERY_STRING} (^|&)coral-no-serve$
RewriteRule   ^(.*)$ http://cache.meinedomain.tld/$1           [R,L]


#Folgender Block prueft ob die load zu hoch ist und
#redirected dann auf den gecachten cache...
#RewriteMaps muessen global in der vhost konfig gemacht werden.
RewriteCond %{REMOTE_ADDR} !^127.0.0.1$
RewriteCond %{REMOTE_ADDR} !^IP_DES_CACHES$
RewriteCond %{HTTP_USER_AGENT} !^CoralWebPrx
RewriteCond %{QUERY_STRING} !(^|&)coral-no-serve$
RewriteCond   ${lbwiki:%{REQUEST_URI}|NULL} !^NULL
RewriteRule   ^(.*)$ ${lbwiki:$1|%1}           [R,L]


Wichtig ist hier, dem LoadBalancer einen anderen Namen zu geben.

Wir benutzen für diesen Artikel wieder dasselbe script, so dass direkt auf den Host cache.meinedomain.tld.nyud.net verwiesen wird.

Der erste Block ist eher 'Kosmetik' und verhindert, dass man auf wiki.meinedomain.tld über Coral zugreifen kann.