Reverse Proxy

From SarWiki
Jump to: navigation, search

Einleitung

Zielstellung

Ziel war der Aufbau eines Reverse Proxy Servers, der in der Lage ist, verschiedene Webserver zu konsolidieren und in einem virtuellen Serverbaum darzustellen. Wesentlicher Aspekt dabei war die Fähigkeit zum Modifizieren von Links in angefragten HTML Dokumenten, sowie Cookie-Domain-Angaben und ggf. auch Fehlerausschriften.

Was ist ein Proxy?

Ein Proxy Server ist ein Dienst, der sich als Vermittler zwischen die klassischen Client-Server-Kommunikationsprotokolle setzen kann und damit mindestens zwei Client-Server-Verbindungen realsiert. Die bekanntesten Proxy Server sind Caching Proxy Server für HTTP Anfragen an das Internet. Ein Kunde eines Internet Service Providers, der dessen HTTP Proxy benutzt, schickt alle HTTP Anfragen nicht direkt an das Internet, sondern nur an den Proxy des Providers. Dieser guckt zunächst in seinem Cache nach, ob dieselbe Anfrage schon einmal gestellt wurde und die HTTP Antwort immer noch aktuell ist. Wenn ja, wird die Antwort aus dem Cache an den Client zurückgegeben und so unnötiger Verkehr im Internet vermieden. Ist die Antwort noch nicht in dessen Cache vorhanden, so initiiert der Proxy eine HTTP Anfrage an das eigentliche Ziel, speichert die Antwort im Cache ab und gibt sie zugleich an den Kunden zurück. Auf diese Weise agiert der HTTP Proxy als Mittler zwischen dem Browser auf dem PC des Kunden und dem Webserver im Internet.

Forward und Reverse Proxy

Es gibt nun ganz unterschiedliche Arten von Proxy Servern. Kategorisiert man nach der Topologie, in der sich der Proxy befindet, so lassen sich zwei Proxy Arten unterscheiden: Forward und Reverse Proxy. Der Forward Proxy ist der klassische Proxy, der als Mittler zwischen einem Client und dem Server agiert. Der Client muß dabei speziell konfiguriert sein, um die eigentliche Anfrage statt an den Server, zunächst über den Proxy zu leiten.

Ein Reverse Proxy ist im Gegensatz dazu meist vor verschiedenen Webserver logisch vorgeschaltet und soll den Zugriff auf diese Beschränken und so mehr Sicherheit geben. Der Client muß hier nicht speziell konfiguriert werden. Für ihn erscheint der Proxy wie ein ganz normaler Server. Hier liegt die Konfiguration viel mehr auf der Proxyseite. Der Proxy muss nun genau wissen, wohin er welche Anfragen leiten muss. Die erhaltenen Antworten muss der Proxy ggf. umschreiben, sich selber als Absender ausgeben und dann an den Client zurückgeben.

Einsatzszenario

Klassischerweise wird ein solcher Proxy zum Erhöhen der Sicherheit eingesetzt. Betrachten wir zum Beispiel das folgende Szenario. Eine Firma ist direkt an das Internet angeschlossen und betreibt einen internen Webserver, auf dem verschiedene Dienste laufen. Genau ein Dienst davon (z.b. http://serverA/dienst1) soll auch im Internet verfügbar sein. Aufgrund der Sensibilität der Daten von dienstN (N = 2,3,4 ....), muß gewährleistet sein, dass diese Dienste nicht vom Internet aus erreichbar sind.

+--------+    +--------+    +----------+
|Internet| -- |Firewall| -- |WebserverA|
+--------+    +--------+    +----------+

Die Lösung, in der Firewall einfach den Port 80 aufzumachen, würde zwar der Anforderung genügen, dass der Webserver auch vom Internet aus erreichbar ist (eine entsprechende Virtual Server Funktionalität vorausgesetzt), aber so wäre auch der dienstN (N= 2,3,4 ...) vom Internet aus erreichbar. Dies ist also keine gute Lösung.

Unter Einsatz von mehr Hardware oder besseren Firewalls können nun verschiedene Lösungsansätze präsentiert werden. Ein Ansatz besteht im Einrichten eines Reverse Proxys in der DMZ der Firma.

+--------+    +--------+    +---------------+    +--------+    +----------+
|Internet| -- |Firewall| -- | Reverse Proxy | -- |Firewall| -- |WebserverA|
+--------+    +--------+    +---------------+    +--------+    +----------+

Von draußen erscheint der Reverse Proxy nun wie ein eigener Webserver. Dessen Konfiguration impliziert aber die Weiterleitung aller Anfragen an den Dienst 1 auf dem WebserverA. (http://reverseProxy ---> http://serverA/dienst1) Diese Weiterleitung passiert für den Client völlig transparent und nur in der DMZ bzw. im Netz der Firma. Durch diese Konfiguration ist garantiert, dass nur der Teilbaum /dienst1 im Internet publiziert wird. Durch das o.g. Setup kann so noch der direkte Zugriff vom Internet auf den Webserver verhindert werden.

Umsetzung

Potentielle Lösungen

Im Umfang dieses Seminars war nur die Evaluation von zwei Lösungen realisierbar. Zum einen handelte es sich dabei um das wohl bekannteste OpenSource Projekt zum Thema Proxy: Squid (http://www.squid-cache.org/). Die andere Lösung ist das Modul mod-proxy, das zusammen mit dem Apache Webserver 2.x ausgeliefert wird. Der komplette Webserver ist von http://www.apache.org herunterladbar.

Squid

Obwohl Squid durch vielfältigeste Konfigurationsmöglichkeiten glänzt und eine großartige Cacheverwaltung hat, so findet sich in der Konfiguationshilfe kein Hinweis darauf, wie man den selektiven Zugriff auf den Webserver realsieren kann. Es kann mit wenig Aufwand ein interner Webserver gecached werden. Dabei findet aber immer ein 1:1 Matching statt, d.h. ein Proxy cached auch nur einen Webserver. Geht man hier in den Bereich der Multi-Backends, so wird nach DNS Informationen getrennt, also z.B. nach den Hostnamen in der Anfrage und nicht nach der URL in der Anfrage. Eine solche Konfiguration konnte ich nicht herstellen.

Mod-Proxy

Wesentlich vielversprechender ist da schon der Funktionsumfang des Moduls mod-proxy der Apache Foundation. Dies gestattet das Proxying von Anfragen, je nach URL bzw. nach Pfad im Serververzeichnis und eignet sich damit bestens zur Realisierung des Projektziels. Zusätzlich sind auch zahlreiche Einstellmöglichkeiten enthalten, um die weiteren kleinen Probleme, wie die Umschreibung von Links bzw. die Änderung von Cookie-Domains, zu lösen. Mod-Proxy kann auch mit SSL Anfragen umgehen und somit auch als SSL Gateway fungieren.

Demonstration / Beispiel

Im Rahmen des Projektes wird damit eine Demonstration aufgebaut, die aus drei Servern besteht, die jeweils unter Ubuntu Server LTS 6.06 laufen. Dort ist jeweils ein Apache Webserver 2.0.55 mit dem mod_proxy Version 2.4 installiert. Es wird unbedingt empfohlen, Apache 2.x zu benutzen, da das im Apache 1.x enthaltene mod_proxy nur HTTP 1.0 beherrscht. In späteren Versionen wird aber auch HTTP 1.1 unterstützt. Ein Upgrade wird hier uneingeschränkt empfohlen.

Der prinzipielle Setup sieht so aus:

                                  +-------+
                                  |ServerA|
                                  +-------+
                                 /
+----------+    +---------------+
| Internet +----+ Reverse Proxy | 
+----------+    +---------------+
                                 \
                                  +-------+
                                  |ServerB|
                                  +-------+

Die Dienste von den Servern A und B sind dort jeweils unter http://serverA bzw. http://serverB erreichbar. Wir nehmen weiter an, dass eine Firewall den direkten Zugriff vom Internet auf die Server unterbindet. Nur ein Zugriff auf den Port 80 des Proxys ist zugelassen.

Die Anfragen an den Proxy werden dann wie folgt weitergeleitet:

  • http://revproxy/dienst1 --> http://serverA
  • http://revproxy/dienst2 --> http://serverB

Auch Anfragen auf Unterverzeichnisse sollen adequat weitergeleitet werden, also http://revproxy/dienst1/mydir --> http://serverA/mydir Alle anderen Anfragen werden proxy-lokal beantwortet, d.h. es findet keine Weiterleitung statt.

Die Apache Proxy Module

Wie der Apache Webserver selbst, so ist auch das Modul mod_proxy modular aufgebaut und besteht aus den folgenden Modulen:

  • mod_proxy: The core module deals with proxy infrastructure and configuration and managing a proxy request.
  • mod_proxy_http: This handles fetching documents with HTTP and HTTPS.
  • mod_proxy_ftp: This handles fetching documents with FTP.
  • mod_proxy_connect: This handles the CONNECT method for secure (SSL) tunneling.
  • mod_cache, mod_disk_cache, mod_mem_cache: These deal with managing a document cache. To enable caching requires mod_cache and one or both of disk_cache and mem_cache.
  • mod_proxy_html: This rewrites HTML links into a proxy's address space.
  • mod_headers: This modifies HTTP request and response headers.
  • mod_deflate: Negotiates compression with clients and backends.

(Auschnitt aus dem Handbuch)

Um diese Module bei Ubuntu zu aktivieren sind die Symlinks im Verzeichnis /etc/apache2/mod-enabled aus dem Verzeichnis /etc/apache2/mods-available anzulegen. Anschließend ist der Apache2 neu zu starten. Die Konfigurationsdatei proxy.conf ist ebenfalls in das mods-available Verzeichnis zu linken. Alle folgenden Konfigurationseinstellungen sind in der Datei proxy.conf vorzunehmen. Sie wird automatisch in die Hauptkonfiguration übernommen.

Proxy.conf

Nun soll die Konfigurationsdatei inklusiver aller notwendigen Einstellungen aufgebaut werden, um die obige Situation abzudecken. Zunächst eine

Sicherheitswarnung
Niemals sollte die Option ProxyRequests On gesetzt werden. Damit wird der Proxy zu einem Open Proxy und damit zu einem potentiellen eMail Relay für Spammer bzw. eröffnet die Möglichkeit für weitere mißbräuchliche Nutzung des Servers.

Eine einfache Konfiguration für ein einfaches Proxying basiert auf den folgenden Einträgen in der Datei Proxy.conf

ProxyPass /dienst1/ http://serverA
ProxyPass /dienst2/ http://serverB

Nach dem Einlesen der Konfigurationsdatei (/etc/init.d/apache reload) funktioniert das einfache Mapping durch simples weiterleiten der Verkehrsanfragen. Dies ist jedoch nicht alles. Natürlich ist dies noch nicht alles. So müssen noch alle URLs verändert werden, die potentiell auf serverA oder serverB verweisen.

Werden zum Beispiel Fehlermeldungen zurückgegeben, müssen die entsprechenden Links umgeändert werden. Bei einer Anfrage an: http://revproxy/dienst1/foo wird folgende Fehlermeldung zurückgegeben

HTTP/1.1 302 Found
Location: http://serverA/foo
[...]

ServerA ist für den Client aber bisher unsichtbar geblieben und so sollte das auch bleiben, also müssen solche Meldungen auch verändert werden zu:

HTTP/1.1 302 Found
Location: http://revproxy/dienst1/foo
[...]

Um solche Änderungen durchführen zu lassen ist das Kommando ProxyPassReverse hinzuzufügen. Sinnvollerweise wird dabei die Konfiguration in eine Locationumgebung eingebunden, da wir danach noch weitere Konfigurationen ergänzen werden.

<Location /dienst1/>
     ProxyPassReverse /
</Location>
<Location /dienst2/>
     ProxyPassReverse /
</Location>

Um jetzt auch noch die Cookies ordnungsgemäß setzen zu lassen sind die beiden folgenden Parameter von Bedeutung: ProxyPassReverseCookiePath und ProxyPassReverseCookieDomain.

ProxyPassReverseCookieDomain serverA revProxy
ProxyPassReverseCookieDomain serverB revProxy
ProxyPassReverseCookiePath / /dienst1
ProxyPassReverseCookiePath / /dienst2

Bisher werden nur URLs in HTTP Headern umgeschrieben. In HTML Dateien sind jedoch auch URLs enthalten (CSS Informationen, Links ...), die auch noch umgeschrieben werden müssen. Dafür ist das Modul mod_proxy_html zuständig. Es arbeitet im Prinzip wie ein Output Filter, der die HTML Links entsprechend umschreibt. Die notwendigen Einstellungen dafür sind die folgenden:

  • SetOutputFilter proxy-html
  • ProxyHTMLURLMap

Die erste Option installiert zunächst den HTML Parser als Ausgabefilter. Die zweite Option aktiviert diesen Parser dann für ein gewisses URL Pattern. Der Proxy-html Filter ist im Prinzip ein SAX Parser, der alle HTML 4 und XHTML 1 Regeln kennt und daraufhin den Quelltext nach URLs scannt. Werden welche gefunden, werden diese gemäß der angegebenen Regeln umgeschrieben. Für alle Regeln gilt last match, d.h. die letzte Regel gilt. Um ein mehrfaches URL Rewrite zu verhindern, muss als letztes eine Stopp-Regeln hinzugefügt werden.

<Location /dienst1/>
       ProxyHTMLURLMap / /dienst1/
       ProxyHTMLURLMap /dienst1 /dienst1
</Location>
<Location /dienst2/>
       ProxyHTMLURLMap / /dienst2/
       ProxyHTMLURLMap /dienst2 /dienst2
</Location>

Diese Konfiguration wirkt aber nur für HTML Links bisher. Events, Scripts oder Stylesheets müssen noch separat beachtet werden, da der Parser CSS oder JavaScript nicht parst. Dies ist im Prinzip einfacher Text, der nur mit Search-and-Replace Algorithmen umgeschrieben werden kann. Dazu kann die Option ProxyHTMLExtended benutzt werden, um auch JavaScripts/CSS Files umzuschreiben. Die Beschreibung dessen geht aber über den Scope dieses Manuals hinaus.

Ein letzter Punkt im Zusammenhang mit HTML bleibt aber noch: Compressed HTML. Betrachtet man den folgenden Header:

Content-Type: text/html
Content-Encoding: gzip

so hat man mit der obigen Konfiguration schlicht verloren. Um dies zu umgehen, kann man entweder den ProxyHtmlFilter aufboren mittels

SetOutputFilter INFLATE;proxy-html;DEFLATE

oder Compressed HTML wird einfach abgelehnt, dazu:

RequestHeader unset Accept-Encoding

Ausblick

Folgende Dinge konnten hier noch nicht betrachtet werden.

  • Caching - um den Zugriff zu beschleunigen
  • Content Transformation - live-Überarbeitung des Inhalts entsprechend der Benutzereinstellungen
  • Content Filter - live-Filter für Kinderschutz oder Zugangsschutz