This content was uploaded by our users and we assume good faith they have the permission to share this book. If you own the copyright to this book and it is wrongfully on our website, we offer a simple DMCA procedure to remove your content from our site. Start by pressing the button below!
Liebe Leserin, lieber Leser, an sich ist es gar nicht so schwierig, einen Webserver einzurichten und zu betreiben. Dies jedoch so zu tun, dass der Server stabil, performant und sicher läuft, kann hingegen eine Herausforderung sein. Die Hardware muss richtig dimensioniert, eine geeignete Linux-Distribution ausgewählt und die passenden Dienste installiert werden. Natürlich soll der Server auch Hackern kein Einfallstor bieten und darf ausschließlich dann offline gehen, wenn Sie es wollen. Dieses Buch zeigt Ihnen, wie Sie genau das erreichen. Sie erfahren nicht nur, wie Sie Ihren Server richtig installieren und konfigurieren, sondern auch, wie sie ihn gegen Angriffe härten, ihn überwachen, optimieren, warten und vieles andere mehr. Gerade wenn Sie noch nie einen Webserver aufgesetzt haben, werden Sie von der langjährigen Erfahrung unseres Autors Klaus Rodewig profitieren. Als ausgewiesener Experte für Server-Sicherheit und -Hochverfügbarkeit war er u.a. viele Jahre verantwortlich für das Internetangebot des WDR und das Sportportal der ARD. Aber auch, wenn Sie bereits Administrator sind, werden Sie in diesem Buch noch viel Wissenswertes finden, um das Letzte aus Ihrem Server herauszuholen. Dieses Buch wurde mit großer Sorgfalt geschrieben, lektoriert und produziert. Falls Sie dennoch Anmerkungen und Verbesserungsvorschläge haben, freue ich mich über Ihre Rückmeldung. Und nun viel Spaß bei der Lektüre und gutes Gelingen!
Ihr Stephan Mattescheck Lektorat Galileo Computing
Der Name Galileo Press geht auf den italienischen Mathematiker und Philosophen Galileo Galilei (1564–1642) zurück. Er gilt als Gründungsfigur der neuzeitlichen Wissenschaft und wurde berühmt als Verfechter des modernen, heliozentrischen Weltbilds. Legendär ist sein Ausspruch Eppur se muove (Und sie bewegt sich doch). Das Emblem von Galileo Press ist der Jupiter, umkreist von den vier Galileischen Monden. Galilei entdeckte die nach ihm benannten Monde 1610. Gerne stehen wir Ihnen mit Rat und Tat zur Seite: [email protected] bei Fragen und Anmerkungen zum Inhalt des Buches [email protected] für versandkostenfreie Bestellungen und Reklamationen [email protected] für Rezensions- und Schulungsexemplare Lektorat Stephan Mattescheck Korrektorat Marlis Appel Einbandgestaltung Barbara Thoben, Köln Typografie und Layout Vera Brauner Herstellung Karin Kolbe Satz Typographie & Computer, Krefeld Druck und Bindung Bercker Graphischer Betrieb, Kevelaer Dieses Buch wurde gesetzt aus der Linotype Syntax Serif (9,25/13,25 pt) in FrameMaker. Gedruckt wurde es auf chlorfrei gebleichtem Offsetpapier.
Bibliografische Information der Deutschen Bibliothek Die Deutsche Bibliothek verzeichnet diese Publikation in der Deutschen Nationalbibliografie; detaillierte bibliografische Daten sind im Internet über http://dnb.ddb.de abrufbar. ISBN
Das vorliegende Werk ist in all seinen Teilen urheberrechtlich geschützt. Alle Rechte vorbehalten, insbesondere das Recht der Übersetzung, des Vortrags, der Reproduktion, der Vervielfältigung auf fotomechanischem oder anderen Wegen und der Speicherung in elektronischen Medien. Ungeachtet der Sorgfalt, die auf die Erstellung von Text, Abbildungen und Programmen verwendet wurde, können weder Verlag noch Autor, Herausgeber oder Übersetzer für mögliche Fehler und deren Folgen eine juristische Verantwortung oder irgendeine Haftung übernehmen. Die in diesem Werk wiedergegebenen Gebrauchsnamen, Handelsnamen, Warenbezeichnungen usw. können auch ohne besondere Kennzeichnung Marken sein und als solche den gesetzlichen Bestimmungen unterliegen.
Inhalt 1
Zielsetzung und Planung ......................................................... 1.1
1.2
1.3
2
9 10 11 14 14 14 15 17 19 20
Installation und Konfiguration ................................................ 25 2.1
2.2
2.3
3
Planung ....................................................................................... 1.1.1 Einsatzzweck des Servers ................................................. 1.1.2 Besondere Anforderungen – Risk Management ............... Serverhardware ............................................................................ 1.2.1 Zertifizierte Hard- und Software ...................................... 1.2.2 Dimensionierung des Servers ........................................... Die richtige Distribution .............................................................. 1.3.1 Ubuntu ........................................................................... 1.3.2 Gentoo Linux .................................................................. 1.3.3 Auswahl der passenden Distribution ...............................
9
Einige Detailfragen ...................................................................... 2.1.1 Partitionierung ................................................................ 2.1.2 Welches Dateisystem ist das richtige? ............................. 2.1.3 RAID ............................................................................... Installation .................................................................................. 2.2.1 Gentoo ........................................................................... 2.2.2 Ubuntu ........................................................................... Feintuning ................................................................................... 2.3.1 Paketmanagement einrichten .......................................... 2.3.2 Konfiguration von OpenSSH ............................................ 2.3.3 Benutzer anlegen ............................................................ 2.3.4 Konfiguration der Bash .................................................... 2.3.5 Umask .............................................................................
Tools ........................................................................................... Patchmanagement ....................................................................... 7.2.1 Patchmanagement mit Ubuntu ........................................ 7.2.2 Patchmanagement mit Gentoo ........................................ 7.2.3 Schwierigkeiten beim Patchmanagement ........................ Den Überblick behalten ............................................................... Rechtliches .................................................................................. Zusammenfassung ........................................................................
396 396 397 404 408 409 410 412
Index ............................................................................................................ 415
7
Only wimps use tape backup: real men just upload their »important stuff on ftp, and let the rest of the world mirror it«. Linus Torvalds
1
Zielsetzung und Planung
In diesem Kapitel werden die grundlegenden Fragen erörtert, mit denen Sie sich auseinandersetzen sollten, bevor Sie einen Server betreiben können. Dies betrifft zum Beispiel den Einsatzzweck Ihres Servers, die Risiken sowie die geeignetste Hardware und Linux-Distribution.
1.1
Planung
Es gibt viele Gründe, einen eigenen Server zu betreiben. Manche Menschen treibt die pure Lust an der Materie, andere – wahrscheinlich die meisten – verfolgen einen bestimmten Zweck. Im privaten Bereich kann das die Veröffentlichung einer eigenen Website sein, für die ein Standardpaket bei einem der einschlägigen Webhoster nicht geeignet ist, oder der Betrieb eines Chatservers oder eines Spieleservers. In Firmen wird der Betrieb eines eigenen Servers häufig aus Kosten- und Sicherheitsgründen erwogen. Standardangebote von Providern sind meist nur für Privatkunden ausgelegt und kommerzielle Angebote entsprechend kostspielig. Hinzu kommt, dass nicht jede Firma ihre sensiblen Daten auf Systemen ablegen möchte, auf die andere Personen – die Administratoren des Providers – Zugriff haben. Gründe für den Betrieb eines eigenen Servers gibt es also viele – leider auch mindestens genauso viele Fußangeln. Dieses Buch soll Ihnen helfen, bekannte Fußangeln zu vermeiden, und Sie in die Lage versetzen, einen eigenen Server zu planen, zu installieren und sicher zu betreiben. Es behandelt ausschließlich die Einrichtung und den Betrieb von Servern mit Linux. Auf einen generischeren Ansatz, der auch echte Unix-Systeme wie FreeBSD oder OpenBSD umfasst, habe ich bewusst verzichtet. Zum einen führt ein generischer Ansatz immer zu einer weniger detaillierten Beschreibung der einzelnen Themen, zum anderen sind sich – dank des POSIX-Standards – auf Unix basierende Betriebssysteme und Linux in
9
1
Zielsetzung und Planung
der Regel so ähnlich, dass im Einzelfall die mit Linux gelernten Techniken einfach auf Unix-basierende Betriebssysteme transferiert werden können. Die Anhänger der reinen Lehre bzw. der freien Software bezeichnen Linux als GNU/Linux, da es – also der Kernel selbst – in der Regel nur im Zusammenspiel mit einer großen Anzahl von GNU-Tools zu gebrauchen ist. In diesem Buch werde ich pragmatisch und unpolitisch die Bezeichnung Linux ohne Zusatz verwenden. Puristen mögen mir dies nachsehen. Darüber hinaus meine ich mit Linux wirklich nur Linux und nicht Unix. Obgleich häufig in denselben Topf geworfen, sind Linux und Unix zwei verschiedene Dinge. Linux sieht aus wie Unix, fühlt sich an wie Unix, »schmeckt« wahrscheinlich auch wie Unix, ist aber kein Unix. Als Unix werden die Betriebssysteme bezeichnet, die wirklich organische Nachkommen des Ur-Unix sind. Dies sind insbesondere die verschiedenen BSDVarianten, Solaris, Mac OS X, HP-UX und AIX. Alle diese Systeme können auf eine gemeinsame Codebasis zurückgeführt werden.1 Linux hingegen wurde Anfang der 90er Jahre »aus dem Nichts« erschaffen, ohne Verwendung von Unix-Code.
1.1.1
Einsatzzweck des Servers
Wie bei den meisten Dingen im Leben werden die wichtigsten Entscheidungen für den Betrieb eines Servers vor der Installation getroffen. Am Anfang wird eine Überlegung zu Sinn und Zweck des Servers stehen. Daran anschließen sollte sich die Erstellung einer (in der Praxis wahrscheinlich mehr oder weniger) klar formulierten Liste von Anforderungen. Zu diesem Zeitpunkt ist es weniger wichtig, sich in technische Details der Betriebssystem- und Dienste-Installation zu ergehen, als vielmehr Rahmenbedingungen für die Themen abzustecken, die sich im Nachhinein nur mit erhöhtem Aufwand ändern lassen. Dies umfasst insbesondere die Auswahl und Dimensionierung der Hardware, die Auswahl eines geeigneten Standortes (Provider) für den Server und die klare Formulierung der Anforderungen an Verfügbarkeit und Schutzbedarf des Systems. Als Hilfestellung können Sie die folgende Frageliste verwenden. Sie erhebt keinen Anspruch auf Vollständigkeit – dazu sind die individuellen Anforderungen einfach zu unterschiedlich –, deckt aber die vier wichtigsten Punkte Performance, Speicherbedarf, Verfügbarkeit und Schutzbedarf ab. 왘
Welche Dienste soll der Server anbieten?
왘
Wie viele Benutzer werden gleichzeitig auf dem Server arbeiten?
왘
Wie hoch ist der Schutzbedarf des Servers?
왘
Welche Arten von Daten sollen auf dem Server verarbeitet werden?
왘
Wie groß ist das zu erwartende Datenvolumen auf dem Server?
1 http://www.levenez.com/unix/
10
Planung
왘
Wie groß ist das über die Internetanbindung zu erwartende Datenübertragungsvolumen?
왘
In welchem Ausmaß wird sich das Datenvolumen im Zeitraum x voraussichtlich ändern?
왘
Wie hoch soll die Verfügbarkeit des Systems sein?
왘
Wie schnell muss das System nach einem Ausfall wiederhergestellt sein?
1.1.2
Besondere Anforderungen – Risk Management
Aus der vorstehenden Liste können sich besondere bzw. erhöhte Anforderungen an ein System ergeben, beispielsweise hinsichtlich der Verfügbarkeit. Soll die Erreichbarkeit eines Servers weder durch geplante (Wartung) noch durch ungeplante Ereignisse (Angriff, Defekt, Fehler etc.) beeinträchtigt werden, kommt man nicht umhin, besondere Vorkehrungen zu treffen und mit technischen Mitteln Redundanz herzustellen. Solche erhöhten Anforderungen bestehen insbesondere bei kommerziell genutzten Systemen. Eine Firma beispielsweise kann sich heutzutage kaum mehr den Ausfall ihres Mailservers erlauben. In Abhängigkeit von der gewünschten Verfügbarkeit kann dies auf verschiedene Arten realisiert werden. Um Ereignisse wie Stromausfall oder den Ausfall einer Netzwerkverbindung aufzufangen, reicht ein Server mit doppelten Netzteilen und zwei Netzwerkkarten. Die Netzteile müssen dann allerdings auch an getrennte Stromversorgungen angeschlossen werden, was einen erhöhten Aufwand nicht nur für den Server, sondern auch für die Infrastruktur bedeutet, in welcher der Server betrieben werden soll. Dasselbe gilt für eine redundante Netzwerkanbindung. Eine Netzwerkkarte allein reicht nicht, um Redundanz herzustellen, das würde nur den Ausfall der anderen Netzwerkkarte im Server ausgleichen. In der Regel werden redundante Netzwerkanbindungen verwendet, um Fehler in der gesamten Netzwerkinfrastruktur aufzufangen. Das bedeutet, dass eben diese Infrastruktur auch redundant aufgebaut sein muss, von allen lokal verwendeten Netzwerkgeräten (Switch, Hub, Router, Gateway etc.) bis hin zur Internetanbindung. Vor dem Hintergrund, dass das Herbeiführen einer größtmöglichen Redundanz, die alle erdenklichen Ereignisse abdeckt, nahezu unmöglich ist, da die Kosten dafür sehr schnell in einen unwirtschaftlichen Bereich steigen, sollte vor dem Formulieren von Maßnahmen für besondere Anforderungen immer erst eine Risikoabschätzung durchgeführt werden. Im professionellen Umfeld eines Information Security Management Systems (ISMS), das durch die ISO-Norm 27000 beschrieben wird und auf das im Laufe des Buches noch häufiger verwiesen wird, wird dieser Prozess als Risk Management bezeichnet und stellt die Grundlage aller Maßnahmen dar, mit denen Informationssicherheit gewährleistet werden soll.
11
1.1
1
Zielsetzung und Planung
Die grundsätzliche Idee eines Risk Managements ist, dass wirkungsvolle Maßnahmen zur Vermeidung oder Minimierung von Risiken nur dann möglich sind, wenn die entsprechenden Risiken bekannt sind. Daher steht am Anfang eines Risk Managements die Erfassung möglicher Risiken. Die im Rahmen dieser Erfassung betrachteten Risiken müssen natürlich in einem Zusammenhang mit den zu betrachtenden Systemen und den damit verbundenen relevanten Prozessen stehen. Für einen geschäftlich genutzten Server wären dies in erster Linie die Geschäftsprozesse, die auf das Funktionieren des Servers angewiesen sind. Mögliche zu betrachtende Risiken, die für einen Server im Internet unabhängig von seiner Wichtigkeit für Geschäftsprozesse bestehen, sind beispielsweise Angriffe auf Netzwerk- oder Applikationsebene. Geeignete Maßnahmen zur Behandlung dieser Risiken wären eine zeitgemäße Härtung des Systems und die Verwendung sicherer Applikationen. Im Bereich der Verfügbarkeit eines Systems bestehen zahlreiche Risiken, die zu einer Nichtverfügbarkeit des Servers und damit der von diesem Server angebotenen Dienste führen können: 왘
Stromausfall
왘
Ausfall der Internetanbindung
왘
Hardwaredefekt
왘
Ausfall des Rechenzentrums
왘
Softwarefehler
왘
Fehlbedienung
왘
etc.
Eine rein technische Betrachtungsweise dieser Risiken würde leicht zu Gegenmaßnahmen führen, die zwar effektiv, vermutlich aber nicht besonders effizient sind. Effizienz drückt sich beim Risk Management dadurch aus, dass die Ausgaben für Maßnahmen gegenüber dem wirtschaftlichen Schaden, der sich aus den Risiken ergeben kann, abgewogen werden müssen. Das bedeutet, dass zum einen die Wahrscheinlichkeit eines Risikos betrachtet werden muss und zum anderen die möglichen finanziellen Auswirkungen, die durch den Eintritt des Risikos entstehen können. Dieser Betrachtung müssen die Kosten für die Behandlung des Risikos gegenübergestellt werden. Es gibt vier Möglichkeiten, ein Risiko angemessen zu behandeln: 왘
geeignete Maßnahmen treffen, um das Risiko zu minimieren
왘
das Risiko akzeptieren
12
Planung
왘
das Risiko vermeiden
왘
die Verantwortung an Dritte übertragen
Der Ausfall einer Festplatte z. B. kommt statistisch gesehen wahrscheinlich häufiger vor als der Brand in einem Rechenzentrum. Aus diesem Grund ist es empfehlenswert, einen Server mit einem RAID-System zu betreiben, so dass der Ausfall einer Festplatte nicht zum Ausfall des gesamten Servers führt. Hinzu kommt, dass die Kosten für ein RAID-System heutzutage zu vernachlässigen sind. Ergo: Eine kostengünstige, effiziente Risikobehandlung durch Einführung einer geeigneten Maßnahme. Ist die Wichtigkeit des Servers nicht so hoch, dass die Verwendung eines RAIDSystems notwendig ist – z. B. weil der Server nur als Testsystem verwendet wird, dessen Ausfall keine Auswirkungen auf den Geschäftsbetrieb hätte –, kann das Risiko des Festplattenausfalls akzeptiert werden. Das bedeutet, dass der Server ohne RAID-System verwendet wird und im Fall eines Festplattendefektes das System neu eingerichtet wird. Für die dritte Möglichkeit, das Vermeiden eines Risikos, lässt sich im Zusammenhang mit dem Festplattenschaden keine Analogie finden, denn ein Server, der zur Risikominimierung ohne Festplatte betrieben wird, ist kaum praktikabel. Ein passendes Beispiel ist jedoch das Risiko eines Ausfalls durch Fehlbedienung. Eine Fehlbedienung kann z. B. vorliegen, wenn ein Benutzer dauerhaft mit Root-Rechten arbeitet. Um dieses Risiko zu vermeiden, kann das Arbeiten mit solchen Rechten durch entsprechende Vorgaben und Richtlinien verboten werden. Nicht jedes Risiko kann minimiert, vermieden oder akzeptiert werden. In einem solchen Fall besteht die angemessene Behandlung darin, das Risiko an Dritte zu übertragen. Dies kann durch Abschließen einer Versicherung geschehen, mit der die finanziellen Auswirkungen eines Ereignisses minimiert werden, oder durch Abschließen geeigneter Service Level Agreements z. B. mit dem Provider, bei dem das System gehostet wird. Ein Risk Management versetzt Sie in die Lage, einen objektiven Überblick über notwendige Maßnahmen zu bekommen, die für den sicheren Betrieb eines Servers (oder einer Infrastruktur) notwendig sind. Denn eins ist sicher: Fragen Sie einen Administrator nach Maßnahmen zur Behandlung eines Risikos, werden Sie mit sehr hoher Wahrscheinlichkeit als Antwort eine technisch brillante Lösung bekommen, die aber kaum zu finanzieren ist. Fragen Sie hingegen Ihren Controller, wird Ihnen dieser eine finanziell überaus attraktive Lösung anbieten, die aber technisch vollkommen ungeeignet ist. Ein konsequent durchgeführtes Risk Management vereint beide Positionen – die klassische Win-win-Situation.
13
1.1
1
Zielsetzung und Planung
1.2
Serverhardware
In den letzten Jahren ist die Hardwareunterstützung von Linux so gut geworden, dass es bei Verwendung gängiger Hardware kaum noch Probleme gibt, Linux ans Laufen zu bringen. Probleme bereiten vereinzelt noch Multimediageräte oder Beschleunigerfunktionen von Grafikkarten, wohingegen sich die Beschaffung von Hardware für den Servereinsatz nicht mehr als sehr schwierig erweist. Es gibt zahlreiche Datenbanken im Netz, bei denen man sich – zum Teil distributionsspezifisch – über die Unterstützung von Hardware durch Linux informieren kann. Einige der bekannten Hardwaredatenbanken sind die folgenden: URL
Distribution
http://developer.novell.com/yessearch/Search.jsp
Novell
http://wiki.ubuntuusers.de/Hardwaredatenbank
Ubuntu
http://en.opensuse.org/Hardware
openSUSE
http://www.tldp.org/HOWTO/Hardware-HOWTO/
Debian
Tabelle 1.1 Hardwaredatenbanken im Internet
1.2.1
Zertifizierte Hard- und Software
Abschnitt 1.3 enthält einige Tipps und Hinweise zur Auswahl einer geeigneten Linux-Distribution für den eigenen Server. Es kann allerdings sein, dass man sich als Benutzer die zum Einsatz kommende Distribution nicht immer aussuchen kann. Viele Hosting-Provider bieten beispielsweise nur einige wenige Distributionen an, häufig Debian und openSUSE. In einem solchen Fall fällt die Wahl nicht schwer, letzten Endes kann der persönliche Geschmack entscheiden. Schwieriger wird es, wenn die einzusetzende Soft- oder Hardware eine konkrete Distribution voraussetzt. Bestimmte Hardwarehersteller leisten beispielsweise nur dann Support im Rahmen eines Wartungsvertrages, wenn ein für die betreffende Hardware zertifiziertes Betriebssystem eingesetzt wird. Falls Sie also planen, Serverhardware einzusetzen, für die ein Wartungsvertrag abgeschlossen werden soll, sollten Sie genau prüfen, ob dieser Wartungsvertrag vom eingesetzten Betriebssystem abhängig ist. Für die Distribution Ubuntu finden Sie eine Liste der zertifizierten Hardware auf der Webseite http://webapps.ubuntu.com/certification/.
1.2.2
Dimensionierung des Servers
Computerhardware ist heutzutage so leistungsfähig geworden, dass es sich für einen dedizierten Server kaum mehr lohnt, umfangreiche Planungen zur Dimen-
14
Die richtige Distribution
sionierung der Hardware anzustellen. Desktop-PCs kommen mittlerweile mit Mehrfachkern-Prozessoren und Festplatten in Terabyte-Größe daher, und selbst Notebooks vom Lebensmitteldiscounter verfügen über eine RAM-Ausstattung, die vor wenigen Jahren noch so manchen Serveradministrator vor Neid hätte erblassen lassen. Lenken Sie Ihr Augenmerk daher weniger auf die Leistungsparameter als auf Punkte wie einfache Wartbarkeit, Hotplug-Festplatten und ausreichend Platz für zusätzliche Hardware (RAID-Controller, Festplatten, Speichererweiterungen etc.).
1.3
Die richtige Distribution
Es gibt mittlerweile eine nahezu unüberschaubare Anzahl von Linux-Distributionen. Die Website www.distrowatch.com, eine Seite mit Rankings und Informationen zu verschiedenen Linux-Distributionen, ist eine gute Informationsquelle. Die große Anzahl der Distributionen rührt daher, dass es verschiedene Distributionen für spezielle Einsatzgebiete gibt. Für einen Server, der nicht nur zum Ausprobieren einer Linux-Distribution betrieben werden soll, empfiehlt es sich, eine der »großen« Distributionen zu verwenden. Distrowatch führt diese als »Major Distributions« in einer Top-Ten-Liste.2 Den Großteil dieser Distributionen machen diejenigen aus, die mit Binärpaketen ausgeliefert werden und deren Paketmanagement (normalerweise) Binärpakete verwaltet. Das Betriebssystem kommt vorkompiliert von CD, alle zusätzlich installierte Software wird ebenfalls bereits vorkompiliert zum System hinzugefügt. Natürlich kann sich der Anwender einen eigenen Kernel erstellen oder beliebige Software aus dem Quelltext übersetzen, dies stellt aber nicht den grundlegenden Mechanismus dieser Distributionen dar. Innerhalb dieser Gruppe von Distributionen kann man unterscheiden zwischen den Distributionen mit Debian-Paketmanager (Debian, Ubuntu und Knoppix etc.) und denen mit RPM-Paketmanager (Novell SUSE, openSUSE, Red Hat, Fedora, Mandriva, PCLinuxOS etc.). Beide Paketmanager verrichten ihre Arbeit und sind in etwa gleich einfach oder schwierig zu bedienen, so dass sie nicht als primäres Entscheidungskriterium für eine Distribution herangezogen werden sollten. Auch wenn man aus Gewohnheit zu »seinem« Paketmanager tendiert … Gewohnheit ist ein schlechter Ratgeber. Unter den großen Distributionen gibt es neben denen mit Debian- oder RPM-Paketmanager die beiden Außenseiter Slackware und Gentoo. Slackware ist eine der 2 http://distrowatch.com/dwres.php?resource=major
15
1.3
1
Zielsetzung und Planung
ältesten Linux-Distributionen. Manche würden sie als spartanisch bezeichnen, andere als benutzerunfreundlich. Der Paketmanager prüft beispielsweise keine Abhängigkeiten zwischen Paketen, was gleichzeitig ein Pluspunkt und ein Minuspunkt sein kann. Ein Pluspunkt deswegen, weil die automatische Installation nicht benötigter Pakete entfällt, ein Minuspunkt, weil sich der Benutzer selbst um die Erfüllung von Abhängigkeiten kümmern muss. Gentoo ist der Exot unter den Linux-Distributionen – eine so genannte Meta-Distribution. Das Prinzip von Gentoo besteht darin, dass der Anwender sein gesamtes System selbst aus dem Quelltext übersetzt. Hierzu bedient sich Gentoo seines eigenen Paketmanagers (Portage). Das Grundsystem selbst wird bei der Installation kompiliert, alle nachträglichen Erweiterungen werden ebenfalls vom Anwender bzw. vom Paketmanager kompiliert. Der Anwender erhält auf diese Weise ein optimal an seine Hardware angepasstes System und muss darüber hinaus nicht fürchten, über nicht (ohne weiteres) analysierbare Binärsoftware sein System zu kompromittieren. Ob nicht überprüfter Quelltext allerdings eine größere Sicherheit bietet, sei jedem selbst überlassen – wer liest schon den Quelltext jeder Software, die er installiert? Neben rein technischen Unterscheidungsmerkmalen spielt ein organisatorischer Aspekt bei der Auswahl einer Distribution eine wichtige Rolle: der Support. Linux ist zwar ein freies System, und auch auf dem Server verwendete Software ist in der Regel freie Software, so dass man das Betriebssystem samt Zusatzsoftware in Eigenregie pflegen kann, allerdings müsste man dazu Dutzende bis Hunderte verschiedene Softwarepakete ständig auf Aktualität prüfen und gegebenenfalls manuell Updates einspielen. Moderne Distributionen nehmen einem diese Arbeit durch ihren Paketmanager ab. Dieser prüft selbstständig, ob Updates für die installierte Software vorhanden sind, und installiert diese ebenso selbstständig. Der Anwender braucht sich nur um das regelmäßige Durchführen des Update-Prozesses zu kümmern. Allerdings funktioniert dieser Mechanismus nur so lange, wie der jeweilige Distributor Updates für die betreffende Distribution anbietet. Ein wichtiges Kriterium für die Auswahl einer Distribution ist daher die Laufzeit des Supports. In diesem Buch kommen zwei Distributionen zum Einsatz: Ubuntu und Gentoo. Dass beide Distributionen auch von namhaften Hardwareherstellern als für den professionellen Gebrauch geeignet angesehen werden, zeigen die vielen mittlerweile vorhandenen Zertifizierungen. So sind beide Distributionen von Sun Microsystems für die Niagara-Plattform zertifiziert. Ubuntu wird von der Firma Dell auf verschiedenen Rechnermodellen vorinstalliert angeboten, und IBM hat Ubuntu für den Einsatz der Datenbank DB/2 zertifiziert.
16
Die richtige Distribution
1.3.1
Ubuntu
Ubuntu ist eine relativ junge Distribution. 2004 erschien die erste Version, und seitdem ist Ubuntu zu einer der am meisten genutzten Distributionen geworden. Ubuntu basiert auf dem Debian-Paketmanager und verwendet Gnome als Standarddesktop. Entwickelt und gepflegt wird Ubuntu von der Firma Canonical, die das System kostenlos im Internet und auf CD verbreitet. Der normale Lebenszyklus einer Ubuntu-Distribution beträgt 18 Monate. Darüber hinaus gibt es so genannte LTS-Versionen von Ubuntu (LTS steht für Long Term Support), die drei bzw. fünf Jahre mit Updates versorgt werden. Drei Jahre Support erhält dabei die Desktop-, fünf Jahre die Serverversion. Die Desktopversion ist für den Betrieb als Arbeitsplatzrechner optimiert und bringt neben Gnome zahlreiche Anwenderprogramme mit. Die Serverversion ist in ihrer Ausstattung spartanischer und kommt ohne grafische Oberfläche und Büroprogramme daher. Sie wird in diesem Buch die Grundlage aller auf Ubuntu basierenden Beispiele sein. Ubuntu 6.06 Dapper Drake war die erste LTS-Version und ist im Juni 2006 erschienen. Kleiner Tipp zu Ubuntu-Versionsnummern Die Versionsnummern von Ubuntu setzen sich immer aus der Jahres- und der Monatszahl des Erscheinungsdatums zusammen. Dapper Drake ist im Juni 2006 erschienen und trägt die Versionsnummer 6.06. Der Nachfolger, Edgy Eft, hat die Versionsnummer 6.10 und ist im Oktober 2006 erschienen. Feisty Fawn, Versionsnummer 7.04, erschien im April 2007 und Gutsy Gibbon, Versionsnummer 7.10, im Oktober 2007. Ist Ihnen noch etwas aufgefallen? Genau, die Anfangsbuchstaben der Versionsnamen folgen dem Alphabet.
Der Support für die Serverversion von 6.06 läuft noch bis zum Juni 2011. Das bedeutet, dass man als Serverbetreiber noch eine Menge Zeit bis zum nächsten Distributionswechsel hat, wenn man 6.06 verwendet. Ein ganz wichtiger Punkt dabei ist, dass sich der Support nur auf das Beheben von Fehlern oder Sicherheitslücken bezieht, nicht aber auf die Verfügbarkeit einer neuen Funktionalität. Größere Änderungen in Softwarepaketen können daher nur über ein Distributionsupgrade oder manuelles Einspielen erfolgen, nicht aber über den Support der Distribution. Bis zum Erscheinen von LTS-Ubuntu war Support mit einer solch langen Laufzeit ausschließlich den so genannten Enterprise-Distributionen vorbehalten. Enterprise-Distributionen sind z. B. der Novell SUSE Linux Enterprise Server oder Red Hat Enterprise Linux (RHEL). Beide Distributionen verfügen über lange Support-
17
1.3
1
Zielsetzung und Planung
zeiten – Novell bietet für den Enterprise Server fünf Jahre Support, Red Hat für den RHEL sieben Jahre –, sind aber kostenpflichtig. Da die Zielgruppe für diese Distributionen Firmenkunden sind, sind die Preise für Privatleute naturgemäß sehr hoch. Ein Grund für den Einsatz dieser kostenpflichtigen Distributionen kann darin bestehen, dass bestimmte Hard- oder Software für die Verwendung einer der beiden Distributionen vom Hersteller zugelassen ist. Bis zum Erscheinen von Ubuntu 6.06 LTS wurden kostenlose Distributionen von vielen Soft- und Hardwareherstellern schlicht ignoriert. Mittlerweile beginnt sich die Situation aber zu ändern, und immer häufiger ist Ubuntu in der Liste der unterstützten Distributionen zu finden. Die Firma Dell liefert mittlerweile Desktops, Notebooks und Serversysteme mit vorinstalliertem Ubuntu aus, Sun Microsystems unterstützt neben dem Novell SUSE Enterprise Server und RHEL auch Ubuntu 6.06 LTS auf seinen T1-Systemen. Ubuntu besticht durch einfache Bedienbarkeit, einen gut geplanten und kommunizierten Release-Zyklus, lange Supportzyklen für die LTS-Versionen, den bewährten Debian-Paketmanager und eine mittlerweile große und gut organisierte deutschsprachige Community mit Portalen wie z. B. www.ubuntuusers.de. Ein Nachteil bei Ubuntu ist die zum Teil sehr unsichere Standardkonfiguration der Programmpakete. Den eisernen Grundsatz »Secure by Default« scheint man bei Ubuntu nicht allzu wichtig zu nehmen. Von einer Enterprise-Distribution sollte man allerdings ein anderes Verhalten erwarten können. Neben der mit Gnome ausgelieferten Standardversion gibt es verschiedene Ubuntu-Projekte, die sich in Art und Umfang der Pakete oder in den verwendeten Desktopsystemen und Fenstermanagern unterscheiden. Das Projekt Kubuntu ist ein Ubuntu, das mit KDE statt mit Gnome ausgestattet ist. Xubuntu verwendet den Xfce Windowmanager und ist damit für den Einsatz auf älteren Systemen geeignet. Neben freier Software ist für Ubuntu auch so genannte urheberrechtlich eingeschränkt verwendbare und proprietäre Software über das distributionseigene Paketmanagement verfügbar. Dies erleichtert die Verwendung solcher Software ungemein, denn bei Distributionen, die ausschließlich freie Software verwenden, muss diese Software händisch installiert und gepflegt werden. Bäumchen, wechsle dich! Aus einem »normalen« Ubuntu lässt sich auch im Nachhinein leicht ein Kubuntu machen (und umgekehrt): sudo apt-get install kubuntu
18
Die richtige Distribution
1.3.2
Gentoo Linux
Wie weiter oben bereits erwähnt, ist Gentoo eine Meta-Distribution – eine Distribution, die vom Benutzer selbst aus dem Quelltext übersetzt wird. Dadurch kann das System ideal an vorhandene Hardware angepasst werden. Gentoo setzt dabei ein fundiertes Verständnis von Linux voraus, denn der Benutzer muss sich bereits bei der Installation um viele Dinge kümmern, die ihm bei anderen Distributionen von entsprechenden Tools abgenommen werden. Die Zielgruppe von Gentoo ist damit klar: versierte Linux-Benutzer. Falls Sie nicht dazuzählen, aber experimentierfreudig sind, sollten Sie eine Begegnung mit Gentoo nicht scheuen. Wenn Sie ein Gentoo-System mit allen Feinheiten ans Laufen bekommen haben, werden Sie eine ganze Menge über Linux gelernt haben. Ein großer Vorteil von Gentoo ist – neben der optimalen Anpassung an die Hardware – die große Auswahl an verfügbarer Software. Ein gewichtiger Nachteil ist dagegen der mitunter große Zeitaufwand beim Einspielen umfangreicher Updates, denn diese müssen ja alle aus dem Quelltext übersetzt werden. Auch ist es in der Vergangenheit schon öfter vorgekommen, dass sich die Struktur von Konfigurationsdateien geändert hat und einzelne Pakete nach einem Update so lange nicht mehr funktionsfähig waren, bis der Benutzer die Konfigurationsdatei händisch angepasst hat. Nichtsdestotrotz zählt Gentoo als bekanntester Vertreter der Meta-Distributionen zu den für den professionellen Einsatz geeigneten LinuxDistributionen und wird daher in diesem Buch gleichberechtigt neben Ubuntu behandelt. Gentoo kennt keine Versionierung. Die Distribution wird kontinuierlich weiterentwickelt und kann vom Anwender über das Portage-System laufend auf dem aktuellen Stand gehalten werden. Damit entfällt ein Distributionsupdate am Laufzeitende einer bestimmten Version, allerdings erfordern umfangreiche Änderungen am System mitunter einen intensiven Benutzereingriff. Vorsicht mit Programmversionen Ein schwerwiegendes Problem bei Gentoo ist die vereinzelte Verwendung veralteter Software oder von Software im Beta- oder Release-Candidate-Status. Im privaten und semiprofessionellen Umfeld kann dies tolerabel sein, im professionellen Bereich ist dies allerdings recht fragwürdig. Einige der in diesem Buch verwendeten Programmpakete lagen zum Zeitpunkt der Manuskripterstellung nur in Versionen vor, die bekannte Sicherheitslücken aufwiesen. Ob diese Sicherheitslücken von dem jeweiligen PaketMaintainer beseitigt wurden, ohne dass die Paketversion geändert worden ist, sei dahingestellt. Im Zweifelsfall sollten Sie sich nicht darauf verlassen.
19
1.3
1
Zielsetzung und Planung
1.3.3
Auswahl der passenden Distribution
Neben persönlichen Vorlieben gibt es eine Reihe objektiver Faktoren, die man in Betracht ziehen sollte, wenn es darum geht, eine Distribution für einen Server auszuwählen. Das wohl wichtigste Kriterium ist die Frage, ob die einzusetzende Software für die in Frage kommende Distribution überhaupt verfügbar ist. Nicht alle Distributionen bieten den gleichen Umfang an verfügbarer Software. Natürlich kann man sich als Benutzer aus den Quelltexten freier Software selbst Pakete für die eingesetzte Distribution bauen. Bei der Verwendung des Patch- und Update-Mechanismus der Distribution werden die selbstgebauten Pakete allerdings nicht beachtet, so dass jedes selbstgebaute Paket manuell auf Aktualität überwacht und gegebenenfalls händisch aktualisiert werden muss. Bei der Verwendung von Standardsoftware werden Sie damit kaum Probleme bekommen, beim Einsatz eines Servers für ausgefallene Zwecke lohnt sich ein Blick auf die Paketliste einer Distribution aber in jedem Fall. Ein weiteres wichtiges Kriterium ist der von einer Distribution verwendete Paketmanager. Aktuelle Paketmanager bieten zwar alle die wichtigsten Mechanismen zur Paket- und Update-Verwaltung, aber zum einen spielen persönliche Gewohnheiten eine große Rolle, zum anderen gibt es Software von Drittanbietern bisweilen nur für bestimmte Paketmanager vorkonfiguriert. Falls Sie also planen, die Software XY einzusetzen, die nicht Bestandteil der Distribution ist, sollten Sie vorher prüfen, in welchem Format die Software verfügbar ist. Glücklicherweise sind die Zeiten, in denen Software nur für bestimmte Distributionen verfügbar war, weitestgehend vorbei. Schon früh gab es Bestrebungen, Inkompatibilitäten zwischen Distributionen durch einen einheitlichen Standard aufzuheben. In den Urzeiten von Linux unterschieden sich verschiedene Distributionen mitunter recht stark voneinander. Für den Benutzer am auffälligsten war dies an unterschiedlichen Verzeichnisstrukturen zu sehen. Wer sich auf einem SUSE-System im Verzeichnisbaum zurechtfand, war auf einer Slackware oder einem Red Hat mitunter aufgeschmissen. Der Wildwuchs der Systeme war aber weniger ein Problem des Benutzers, als vielmehr ein Problem für SoftwareHersteller. Wollte man eine Software für verschiedene Linux-Distributionen anbieten, mussten nicht nur Installationsroutinen für alle Ziel-Distributionen erstellt werden. Zwischen den verschiedenen Distributionen herrschte auch kaum bis keine Binärkompatibilität. Das bedeutete, dass ein für SUSE kompiliertes Programm u. U. nicht auf einer Slackware lief, weil die System- und Bibliotheksaufrufe nicht die gleichen waren.
20
Die richtige Distribution
Mit der Linux Standard Base3 (LSB) wurde 2001 ein Standard geschaffen, der eine gemeinsame Basis für Linux-Distributionen definiert. Darin finden sich Anforderungen, die eine Distribution erfüllen muss, wenn sie nach dem LSB-Standard zertifiziert werden möchte. Eine LSB-konforme Distribution ermöglicht einem Anwender das schnelle Zurechtfinden im System. Für Software-Entwickler stellt die LSB sicher, dass für eine LSB-zertifizierte Distribution geschriebene Software auch auf einer anderen Distribution funktioniert, die nach derselben LSB-Version zertifiziert ist. Die Version 2.0.1 der LSB ist ISO-Standard. Die Vorgaben der LSB sind umfangreich und umfassen verschiedene Bereiche einer Distribution. Die folgende Liste ausgewählter Punkte gibt einen Überblick über diese Bereiche: 왘
Stack, Heap und andere dynamische Speicher dürfen nicht ausführbar sein.
왘
Es muss das nach System-V-Spezifikation definierte ELF-Objektformat unterstützt werden (Binärkompatibilität).
왘
Es werden genaue Anforderungen an die verwendete libc-Bibliothek definiert.
Es müssen bestimmte Hilfsprogramme installiert sein (z. B. awk, bc, find, gzip, mount etc.). Hierbei orientiert sich die LSB stark am POSIX-Standard.
왘
Der verbindliche Teil des Filesystem-Hierarchy-Standards muss erfüllt sein.
왘
Systemfunktionen wie cron, Init-Skripte und runlevel müssen genau definierten Anforderungen entsprechen.
왘
Benutzer und Gruppenverwaltung müssen dem Standard entsprechen.
왘
Es muss ein Paketmanager vorhanden sein, und dieser muss Installationsroutinen für Software bieten.
왘
System- und Bibliotheksaufrufe müssen dem Standard entsprechend implementiert sein, um die distributionsübergreifende Verwendung von Software zu ermöglichen.
왘
Für den Desktop-Betrieb notwendige Bibliotheken wie QT, gtk und GrafikBibliotheken müssen vorhanden sein.
왘
Python- und Perl-Interpreter müssen einen definierten Umfang besitzen und sich an Vorgaben für Installationsorte halten.
왘
Das Drucksystem muss der Spezifikation des Standards entsprechen.
3 http://www.linuxbase.org/
21
1.3
1
Zielsetzung und Planung
Aufgrund der thematischen Breite der Anforderungen stellt die LSB eine sinnvolle Grundlage für untereinander kompatible Distributionen dar. Für den Anwender wird dadurch das Leben einfacher. War es in der grauen Vorzeit immer ein Vabanquespiel, ein für eine bestimmte Distribution erstelltes Programm auf einer anderen Distribution zu verwenden, ist dieses Problem dank LSB – bei Verwendung zertifizierter Distributionen – heutzutage gelöst. Aus diesem Grund sollte die LSB-Zertifizierung bei der Auswahl einer Distribution unbedingt beachtet werden, denn dadurch erledigen sich eine Menge technischer Probleme von selbst. Nachfolgend sind die darüber hinaus wichtigsten Fragen zur Unterscheidung von Linux-Distributionen aufgeführt. 왘
Welcher Paketmanager wird verwendet, und bietet dieser ein zuverlässiges Update-Management?
왘
Handelt es sich um eine Quelltext- oder eine Binärdistribution?
왘
Ist (kostenpflichtiger) Support verfügbar?
왘
Gibt es angemessene Release-Zyklen?
왘
Ist nur freie Software verfügbar oder auch lizenztechnisch eingeschränkte Software wie z. B. SUN-Java, Hardware-Treiber etc.?
왘
Sind distributionsspezifische Tools und Wizards für Routine-Aufgaben verfügbar?
왘
Ist die Distribution für den Einsatz bestimmter Soft- und Hardware zertifiziert?
왘
Ist die Distribution nach der Linux Standard Base4 zertifiziert?
Die folgenden Tabellen geben einen Überblick über die für den Serverbetrieb wichtigsten Punkte der verbreitetsten Distributionen. Ubuntu
Gentoo
openSUSE
Paketmanager
APT/Debian
Portage
RPM
Typ
binär
Quelltext
binär
Support
왘 왘
Community kostenpfl. bis 24x7
왘
Community
왘 왘
Community 90-Tage-Support für Box-Version
Tabelle 1.2 Überblick über die für den Serverbetrieb wichtigsten Punkte der verbreitetsten Distributionen
Tabelle 1.2 Überblick über die für den Serverbetrieb wichtigsten Punkte der verbreitetsten Distributionen (Forts.)
23
1.3
»Arbeit dehnt sich genau in dem Maß aus, wie Zeit für ihre Erledigung zur Verfügung steht.« Cyril Northcote Parkinson
2
Installation und Konfiguration
In diesem Kapitel erfahren Sie, welche Vorbereitungen Sie für Ihren Server treffen müssen, wie Sie ihn installieren und konfigurieren.
2.1
Einige Detailfragen
Die Anforderungen sind definiert, Hardware beschafft, eine geeignete Distribution ausgewählt – der Installation steht nichts mehr im Weg. Allerdings gibt es noch einige Punkte, die Sie vor der Installation bedenken sollten. Dazu gehören insbesondere die Partitionierung der Festplatte und das zu verwendende Dateisystem. Beides sind Parameter, die sich im Nachhinein nur mit sehr viel Aufwand ändern lassen. Daher ist eine reifliche Überlegung vor Beginn der Installation gut investierte Zeit.
2.1.1
Partitionierung
Nach den Vorüberlegungen steht die eigentliche Arbeit ins Haus. Eine wichtige Frage, die allerdings vor der Installation geklärt werden muss, ist die Aufteilung der Festplatte(n) in geeignete Partitionen. Hierbei gilt es drei Gesichtspunkte zu beachten: Performance, Sicherheit und Bequemlichkeit. Um die Überlegungen zur sinnvollen Partitionierung auf sichere Füße zu stellen, folgt ein kurzer Abstecher in die Theorie des Dateisystem-Layouts. In Kapitel 1, »Zielsetzung und Planung«, wurde der Filesystem Hierarchy Standard (FHS) bereits erwähnt. Der FHS definiert und beschreibt das Layout von Dateisystemen für Unix und Unix-ähnliche Betriebssysteme. LSB-konforme Distributionen müssen den verbindlichen Teil des Standards implementieren. Da die meisten Linux-Distributionen mittlerweile dem FHS entsprechen, können dessen Vorgaben als Grundlage für eine sinnvolle Partitionierung verwendet werden.
25
2
Installation und Konfiguration
Unter Linux befinden sich alle Verzeichnisse unterhalb des Wurzelverzeichnisses. Die folgende Tabelle zeigt die laut FHS notwendigen Verzeichnisse und deren Funktion. Verzeichnis
Funktion
/bin
Enthält Werkzeuge für Administratoren und Benutzer.
/boot
Bootloader und Kernel
/dev
Gerätedateien
/etc
Konfigurationsdateien
/lib
Bibliotheken und Kernelmodule
/media
Mountpoints für Wechselmedien
/mnt
Mountpoint für temporären Gebrauch
/opt
zusätzliche Software
/sbin
für den Betrieb des Systems notwendige Programme
/srv
Daten für Serverdienste
/tmp
temporäre Daten
/usr
zweite Dateisystem-Hierarchie. Programme und Bibliotheken, die nicht für den Systemstart benötigt werden.
/var
bewegliche Daten
/home (optional)
Benutzerverzeichnisse
/lib- (optional)
alternative Bibliotheken
/root (optional)
Benutzerverzeichnis des root-Benutzers
Tabelle 2.1 Erste Verzeichnisebene des FHS
Der FHS unterscheidet zwischen gemeinsam bzw. nicht gemeinsam genutzten Daten und veränderlichen bzw. nicht veränderlichen Daten. Dies ist ein guter Ansatz für eine Partitionierung. Dabei sind statische Daten solche, die nicht vom System im laufenden Betrieb geändert werden. Natürlich werden Konfigurationsdateien, Programme oder Bibliotheken geändert, aber in der Regel nur durch manuellen Eingriff des Administrators im Rahmen von Wartungsarbeiten. Variable Daten sind z. B. Logdateien oder Benutzerdaten, mit denen Benutzer arbeiten (z. B. Dokumente). Gemeinsam genutzte Daten sind solche, die auch von anderen Systemen verwendet werden (können). Das können beispielsweise Programme oder Bibliotheken sein, die auf einem zentralen System installiert und abgelegt werden und die andere Systeme per Netzwerkfreigabe mounten und nutzen. Im Fall eines dedizierten Servers, wie er in diesem Buch beschrieben wird, sind gemeinsam genutzte Daten nicht von Bedeutung. Falls Sie Ihren Server allerdings irgendwann in eine Serverfarm eingliedern möchten, könnte es sein, dass dieses Thema auf Sie zukommt. Bis dahin können Sie es außer Acht lassen.
26
Einige Detailfragen
Alle vom System benötigten statischen Daten können und sollten auf einer gemeinsamen Partition abgelegt werden. Diese umfasst die Verzeichnisse /bin, /boot, /dev, /etc, /lib und /sbin. Der Inhalt dieser Verzeichnisse wird benötigt, um das System zu starten, weswegen die Verteilung auf verschiedene Partitionen und/oder Festplatten das Risiko eines Datenverlustes in diesen Verzeichnissen statistisch erhöht und damit auch das Risiko, das System nicht mehr starten zu können. Im Falle eines Defektes der Startpartition würde es auch nichts nutzen, wenn Teile der statischen Daten auf einer anderen Partition liegen würden – das System müsste ohnehin komplett neu eingerichtet werden. Das Verzeichnis /usr ist eine Besonderheit im Verzeichnisbaum. Es wird auch als sekundäres Dateisystem bezeichnet, da es Programme und Bibliotheken enthält, die nicht für den Systemstart, aber für den Betrieb des Systems benötigt werden. Als Festplattenplatz noch teuer und Festplatten dementsprechend klein waren, wurde das usr-Verzeichnis häufig ausgelagert und zwischen verschiedenen Hosts gleichen Typs geteilt. Festplatten kosten heute nicht mehr viel, das gemeinsame Nutzen von Programmen und Bibliotheken wird höchstens in Serverfarmen verwendet, so dass es kein stichhaltiges Argument dafür gibt, das usr-Verzeichnis auf eine eigene Partition zu legen. Obendrein zählt es auch zu den statischen Verzeichnissen, womit es sich bei den im vorherigen Absatz beschriebenen Verzeichnissen in guter Gesellschaft befindet. Aus Performancegründen können alle Verzeichnisse mit statischen Daten auf derselben Partition untergebracht werden, idealerweise auf einer eigenen, für den Lesebetrieb optimierten Festplatte. Aus Sicherheitsgründen kann diese Partition ohne Schreibzugriff gemounted werden, womit das Verändern von Daten durch falsch oder unzureichend gesetzte Zugriffsrechte unterbunden wird. Über den Ort für die Verzeichnisse /media und /mnt braucht man sich keine Gedanken zu machen; diese Verzeichnisse sind lediglich Mountpoints für externe Datenquellen wie z. B. Netzwerklaufwerke, CD-ROMs, Speicherkarten etc. Das tmp-Verzeichnis wird vom Betriebssystem und den laufenden Prozessen für die Arbeit mit temporären Dateien verwendet. Dabei kann es mitunter passieren, dass wildgewordene oder bösartige Prozesse (z. B. von einem Angreifer eingeschleuste Schadsoftware) das Verzeichnis intensiv mit Daten füllen. Um den Stillstand des Systems durch eine gefüllte Platte zu vermeiden, sollte das tmp-Dateisystem allein aus Sicherheitsgründen auf eine separate Partition ausgelagert werden. Bei Servern, die unter hoher Last und mit vielen temporären Daten arbeiten, ist es empfehlenswert, das tmp-Verzeichnis auf eine eigene Festplatte auszulagern.
27
2.1
2
Installation und Konfiguration
Die Verzeichnisse /home und /root sind Verzeichnisse mit veränderlichen Daten. Unterhalb von /home liegen in der Regel die Verzeichnisse normaler Benutzer, das Verzeichnis /root ist das Benutzerverzeichnis des root-Benutzers. Zumindest für die Verzeichnisse der normalen Benutzer ist es mitunter empfehlenswert, diese auf eine separate Partition auszulagern. Da der root-Benutzer nur sporadisch und mit Bedacht verwendet werden sollte, ist ein Auslagern des root-Verzeichnisses nicht zwingend notwendig. Unterhalb des var-Verzeichnisses liegen Logdateien, Spool-Verzeichnisse (Druckerdienste, Mailserver) und temporäre Dateien, die auch Systemstarts überdauern sollen. Kritisch ist die var-Hierarchie aufgrund der darin enthaltenen Logund Spool-Daten. Logdateien haben die unangenehme Eigenschaft, ständig zu wachsen. Ähnlich wie beim tmp-Verzeichnis kann daher intensives Logging, auch aufgrund unvorhergesehener Ereignisse, dazu führen, dass der gesamte zur Verfügung stehende Festplattenplatz aufgebraucht wird. Dies bewirkt in der Regel den Stillstand eines Systems, mindestens aber merkwürdige Verhaltensweisen. Spool-Dateien, z. B. von einem Mailserver, können plötzlich eine enorme Größe annehmen, wenn der Mailserver beispielsweise keine Größenbeschränkungen für Dateianhänge kennt. Proaktives Monitoring des Systems kann zwar helfen, Engpässe beim Plattenplatz rechtzeitig zu erkennen, aber wer hat schon die Zeit, seinen Server permanent zu überwachen bzw. ständig auf Probleme reagieren zu können? Im Sinne einer vorausschauenden Planung sollte das var-Verzeichnis daher auf eine eigene, ausreichend groß bemessene Partition ausgelagert werden. Da auch in dieser Hierarchie mit viel I/O zu rechnen ist, kann das Verwenden einer eigenen Festplatte sinnvoll sein. Für das srv-Verzeichnis gilt dasselbe wie für die Benutzerverzeichnisse. Eine Trennung von Programm- und Nutzdaten ist grundsätzlich sinnvoll, denn dies erleichtert die Wartung und Erweiterung des Systems. Durch die Verwendung des Logical Volume Managers (LVM) können Partitionen im laufenden Betrieb vergrößert oder verkleinert werden. Dies ist insbesondere für Datenverzeichnisse sehr hilfreich. Die Größe von Programmdateien ist berechenbar und ändert sich nur wenig, für Nutzdaten steht nach Murphys Gesetz aber immer zu wenig Platz zur Verfügung. Stößt eine Partition mit Nutzdaten an ihre Grenzen, kann sie ohne Herunterfahren des Systems mit dem LVM vergrößert werden (ausreichend Festplattenplatz vorausgesetzt). Dies ist nicht möglich, wenn sich die Nutzdaten auf derselben Partition befinden wie die Programmdaten. Darüber hinaus wird es am Ende des Lebenszyklus einer Distribution dazu kommen, dass die installierte Distribution durch eine aktuelle Version ersetzt werden muss. Dies kann durch ein Distributionsupgrade, aber auch durch eine Neuinstallation geschehen. Sind Programm- und Nutzdaten dann auf verschiedenen Parti-
28
Einige Detailfragen
tionen untergebracht, können die Programmdaten bequem aktualisiert werden, ohne dass die Nutzdaten davon beeinträchtigt werden. Zu den im FHS beschriebenen Verzeichnissen kommt noch eine Swap-Partition, die zwar vom FHS nicht gefordert wird, auf einem in der Praxis genutzten System aber zwingend notwendig ist. Die Swap-Partition wird vom Kernel verwendet, um Speicher auszulagern. Daher sollte sie im Idealfall zusammen mit dem tmpVerzeichnis auf eine separate Festplatte ausgelagert werden. Ein Aspekt, der insbesondere im Zusammenhang mit Datenpartitionen interessant ist, ist die Blockgröße des Dateisystems. Durch eine Blockgröße, die an die auf einem Dateisystem abgelegten Daten angepasst ist, lässt sich Festplattenplatz effizient nutzen. Hierzu muss aber im Vorfeld klar sein, welche Art von Daten auf einer Partition abgelegt werden sollen – das Kriterium ist hierbei die Dateigröße. Für die normalen Programmdaten einer Linux-Distribution genügen in der Regel die Standardeinstellungen des Dateisystems. Möchte man an beweglichen Daten aber beispielsweise ausschließlich Dateien mit einer Größe von über 4 KB ablegen, ist es ratsam, die Blockgröße des Dateisystems entsprechend anzupassen (siehe hierzu Abschnitt 2.1.2). Umgekehrt: Für das Ablegen vieler kleiner Dateien ist eine kleine Blockgröße empfehlenswert, um keinen Festplattenplatz zu verschwenden. Für solche Fälle empfiehlt sich das Verwenden einer eigenen Partition, die mit den entsprechenden Parametern formatiert werden kann. Möchte man sich bei der initialen Einrichtung eines Systems bezüglich der Partitionsgrößen noch nicht auf Dauer festlegen, ist der Logical Volume Manager (LVM) die richtige Wahl. Dieser etabliert eine logische Sicht auf eine Festplatte und erlaubt das nachträgliche Ändern von Partitionsgrößen. Die praktische Anwendung wird in Abschnitt 2.2 beschrieben. Ein Aspekt, der am Rande mit Partitionierung zu tun hat, zumindest aber dann, wenn mehrere Festplatten zur Verfügung stehen, ist das Auslagern von Metainformationen des Dateisystems (das Journal) auf eine andere Festplatte. Dies kann die Performance eines Dateisystems signifikant erhöhen. Wie und warum so etwas gemacht wird, beschreibt der folgende Abschnitt. Von den Aspekten des Platzverbrauchs und der Performance abgesehen, kann eine sinnvolle Partitionierung Einfluss auf die Sicherheit eines Systems haben. Partitionen können mit verschiedenen Optionen gemounted werden. So kann eine Partition für Benutzerverzeichnisse häufig mit der Option noexec gemounted werden, was das Ausführen von Programmen auf dieser Partition unterbindet. Dies ist beispielsweise auch für Partitionen sinnvoll, auf denen sich das DocumentRoot eines Webservers befindet. Von einem Webserver ausgelieferte Dateien müssen in der Regel – von CGI-Skripten abgesehen – nicht ausführbar im
29
2.1
2
Installation und Konfiguration
Sinne von Execute-Rechten im Betriebssystem sein. Befindet sich das DocumentRoot eines Webservers auf einer mit noexec gemounteten Partition und kann ein Angreifer über eine Lücke in den Webapplikationen Daten auf dieser Partition ablegen, ist es dem Angreifer dadurch trotzdem nicht möglich, Programme auf dieser Partition auszuführen. Dies ist in den meisten Fällen von Sicherheitslücken in Webapplikationen zwar nur ein schwacher Trost, dennoch folgt dies dem Prinzip des Defense in Depth, das im weiteren Verlauf des Buches noch detaillierter behandelt wird. Die Manpage von mount beschreibt die verschiedenen Parameter zum Mounten von Partitionen. Grundlage der Beispiele in diesem Buch ist eine dreigeteilte Partitionierung: 왘
2 GB Swap-Datei
왘
8 GB Root-Partition
왘
10 GB freier Plattenplatz
Der 10 GB umfassende freie Plattenplatz wird flexibel für die Verwendung des LVM oder das Anlegen weiterer Partitionen verwendet.
2.1.2
Welches Dateisystem ist das richtige?
Nachdem eine sinnvolle Partitionierung gefunden und eingerichtet ist, müssen die erstellten Partitionen mit einem Dateisystem formatiert werden. Die Auswahl eines geeigneten Dateisystems ist mittlerweile etwas schwieriger als in den Anfangszeiten von Linux, da der aktuelle Kernel eine ansehnliche Zahl von verschiedenen Dateisystemen unterstützt. Standard bei Dateisystemen ist schon länger die Verwendung von Journaling-Dateisystemen. Ein Journaling-Dateisystem führt ein Protokoll (Journal) über alle Transaktionen im Dateisystem. Vor einem Schreibvorgang wird der auszuführende Vorgang im Journal vermerkt. Findet dann ein Abbruch des Schreibvorgangs statt, beispielsweise durch einen Stromausfall oder Systemabsturz, kann das Dateisystem anhand des Journals den Zustand von vor dem fehlgeschlagenen Schreibvorgang wiederherstellen. Das Führen des Journals kostet Performance – das Journal muss verwaltet und auf die Festplatte geschrieben werden. Verglichen mit dem Zugewinn an Betriebssicherheit ist diese Performance-Einbuße allerdings zu vernachlässigen, obendrein lassen sich Journaling-Dateisysteme auch auf Performance optimieren, wie weiter unten am Beispiel von ext3 gezeigt wird. Neben der erheblich höheren Stabilität des Dateisystems vermeidet die Verwendung eines JournalingDateisystems zeitaufwendige Prüfungen des Dateisystems nach einem Absturz. Wer zu Zeiten von Nicht-Journaling-Dateisystemen mal einen Absturz eines Server mit entsprechend großen Platten erlebt hat, weiß, dass sich die Prüfung des
30
Einige Detailfragen
Dateisystems über viele Stunden erstrecken kann, was für Produktivsysteme absolut inakzeptabel ist. Angefangen hat Linux mit dem Minix-Dateisystem, das aber aufgrund seiner Limitierungen relativ zügig (1993) vom ext2-Dateisystem abgelöst wurde. ext2 gilt aufgrund seiner langen Entwicklungs- und Praxiszeit als sehr ausgereift und stabil. Mit der Kernel-Version 2.4.15 wurde der Nachfolger ext3 vorgestellt, der auf ext2 aufbaut und als herausstechendste Weiterentwicklung Journaling-Fähigkeiten mitgebracht hat. ext2 wird heute noch vom Kernel-Setup als das Standarddateisystem von Linux bezeichnet, ext3 als das De-facto-Standarddateisystem. Erste Wahl bei aktuellen Distributionen ist ext3, wobei SUSE lange Zeit das ReiserFS als Standardsystem verwendet hat. Dabei handelt es sich um ein hochoptimiertes Dateisystem, das noch vor ext3 das erste Journaling-Dateisystem unter Linux war. Vorteil des ReiserFS war – neben der Journaling-Fähigkeit – die gegenüber ext2 spürbar bessere Performance bei der Verwendung auf Dateisystemen mit vielen Dateien und Verzeichnissen. Wie so häufig im Leben bekommt man aber auch bei Dateisystemen nichts geschenkt. Die gute Performance bezahlt das ReiserFS mit einer – verglichen mit ext2/3 – recht hohen Fehleranfälligkeit, insbesondere bei Abstürzen oder Hardwaredefekten. In Fachkreisen leidgeplagter Administratoren hat dieses Dateisystem daher lange den Spitznamen RasierFS getragen. Unabhängig von seiner technischen Eignung ist das Schicksal des ReiserFS momentan unklar. Mit der Version 4 (Reiser4) wurde das System komplett erneuert und mit zahlreichen neuen Features und Verbesserungen ausgestattet. Tragischerweise ist der Vater und Namensgeber des Reiser-Dateisystems, Hans Reiser, in den USA vor Gericht des Mordes an seiner Frau für schuldig befunden worden. Damit sind Schicksal und aktueller Status seiner Firma Namesys und somit auch des Reiser-Dateisystems unklar. Eine weitere Alternative zu ext3 ist das JFS (Journaled File System), das von IBM für das Betriebssystem AIX entwickelt wurde und mittlerweile für Linux portiert worden ist. JFS unterstützt Access Control Lists und Security Labels, wie sie beispielsweise SELinux verwendet. JFS erlaubt Änderungen am Dateisystem im laufenden Betrieb und ist für hohe Performance und große Datenmengen optimiert. Darüber hinaus gibt es noch das XFS der Firma SGI, das seit der Kernel-Version 2.6 offiziell von Linux unterstützt wird. Wie JFS ist XFS auf hohe Performance und große Datenmengen optimiert, unterstützt Access Control Lists und Quotas und verwendet die so genannte Delayed Allocation Strategy zur Vermeidung von Fragmentierung. Dabei werden zu schreibende Daten möglichst lange im Speicher gehalten, bevor sie auf die Platte geschrieben werden, um einen geeigneten,
31
2.1
2
Installation und Konfiguration
möglichst fragmentierungsfreien Bereich auf dem Datenträger zu finden. Die daraus resultierende geringe Fragmentierung wird mit einer erhöhten Gefahr von Datenverlusten durch plötzliche Ausfälle (Stromausfall, Systemabsturz etc.) erkauft. XFS blickt auf eine lange Geschichte zurück – bereits 1994 ist es für IRIXSysteme implementiert worden. Auch befindet es sich bereits seit einigen Jahren im Linux-Kernel, wodurch es sich auch unter Linux den guten Ruf erworben hat, ein performantes und grundsätzlich robustes Dateisystem zu sein. Für besondere Anforderungen an Performance und Datenmengen ist XFS daher sicher eine gute Wahl – nicht zuletzt wegen der unklaren Situation des Reiser-Dateisystems. Ungeachtet der Vorzüge von Reiser, JFS und XFS in Sachen Performance ist ext3 bei Systemen ohne besondere Anforderungen an Performance immer noch die erste Wahl, und das aus gutem Grund. Als direkte Weiterentwicklung von ext2 fußt es auf einer robusten Codebasis. Genauso wie ext2 ist es seit Jahren das Standarddateisystem unter Linux, und dementsprechend groß sind die Erfahrungen mit diesem System. Die für ext2 vorhandenen Werkzeuge wurden für die Arbeit mit ext3 erweitert, so dass eine ganze Reihe leistungsfähiger Konfigurations- und Diagnosetools zur Verfügung steht. Aufgrund seiner Robustheit sollte vor der Wahl eines alternativen Dateisystems stets geprüft werden, ob sich dadurch wesentliche Vorteile gegenüber der Verwendung von ext3 ergeben. Dies kann der Fall sein, wenn die Hauptlast eines Servers durch Festplatten-I/O erzeugt wird und viele sowie große Daten bewegt werden, beispielsweise bei einem großen File- oder Datenbankserver. Ein Webserver hingegen hat in der Regel nur geringe Anforderungen an die Performance des Dateisystems, die limitierenden Faktoren stellen hier eher CPU und RAM dar. In diesem Buch kommt ext3 als Dateisystem für alle Systeme und Partitionen zum Einsatz. Um die verschiedenen Optimierungsmöglichkeiten von ext3 zu verstehen, ist ein Blick auf die Struktur des Dateisystems unerlässlich. Struktur von ext3 ext3 verwendet zur Strukturierung einer Partition Inodes, Verzeichniseinträge und den Superblock. Die eigentlichen Nutzdaten werden in Blöcken abgelegt, den Datenblöcken. Jeder Datei auf der Partition ist ein Inode zugeordnet. Dieser Inode enthält Informationen über die zu ihm gehörende Datei: 왘
Besitzer (UID, GID)
왘
Zugriffsrechte
왘
Dateigröße
왘
Anzahl der belegten Blöcke
왘
Typ der Datei (Verzeichnis, Datei, Link, Device, Pipe, Socket etc.)
32
Einige Detailfragen
왘
Anzahl der Hardlinks
왘
Zeitstempel der letzten Änderungen (ctime, mtime, atime)
왘
Zeiger auf die eigentlichen Datenblöcke
Über das Programm stat kann man sich die über eine Datei in einem Inode abgelegten Daten anschauen. Für die reguläre Datei mit den Rechten 600 und Benutzer und Gruppe 1111 sieht die Ausgabe wie folgt aus: File: Size: Datei Device: Access: Access: Modify: Change:
Ein interessantes Detail an dieser Stelle ist die Anzahl der im Inode gespeicherten Links (Hardlinks). Ein Hardlink ist eine Verknüpfung im Dateisystem, die auf einen Inode zeigt. Damit kann man Zeiger auf Dateien setzen, die auch dann ihre Gültigkeit behalten, wenn das Ziel verschoben wird. Da ein Inode nur innerhalb desselben Dateisystems eindeutig adressiert werden kann, sind Hardlinks nur innerhalb einer Partition möglich. Darüber hinaus können Hardlinks lediglich für Dateien, nicht aber für Verzeichnisse erzeugt werden. Eine Datei ist nur so lange vorhanden, wie ihr Linkzähler größer als Null ist, weswegen die Angabe über die Links in einem Inode von großer Bedeutung ist. Werden alle Hardlinks auf eine Datei entfernt, wird die Datei gelöscht. Der Systemaufruf zum Löschen einer Datei unter Linux heißt dementsprechend unlink(). Die Anzahl der Links auf eine Datei wird nicht nur durch das Anlegen von Hardlinks erhöht, sondern auch durch das Öffnen einer Datei. Daher kann eine Datei nicht gelöscht werden, solange sie noch von einem Programm geöffnet ist. Die Datei verschwindet in einem solchen Fall zwar aus der Verzeichnisliste, der von der Datei belegte Speicherplatz wird allerdings nicht freigegeben, solange das
33
2.1
2
Installation und Konfiguration
Programm die Datei noch in Benutzung hat. Ein Programmierer würde sagen: »Solange das Programm noch ein Handle auf die Datei geöffnet hat …« Um einen Link über Partitionsgrenzen hinweg zu erzeugen, gibt es Symlinks (symbolische Links). Symlinks sind auch auf Verzeichnisse möglich und zeigen auf Verzeichnis- oder Dateinamen, nicht auf Inodes. Das hat zur Folge, dass das Verschieben des Ziels einen Symlink ungültig werden lässt – er zeigt ins Leere. Für den Benutzer sind Hardlinks und Symlinks in ihrer Funktion nicht zu unterscheiden. Das Setzen eines Symlinks wird allerdings nicht im Ziel-Inode vermerkt, der Linkzähler wird nicht erhöht, weshalb ein Symlink auch nicht vor dem Löschen einer Datei schützt. Der Inode speichert nur Metadaten einer Datei, also Daten, die eine Datei beschreiben. Der eigentliche Dateiinhalt ist in Datenblöcken im Dateisystem abgelegt. Um auf den Dateiinhalt zugreifen zu können, enthält der Inode Zeiger auf die Datenblöcke. Da große Dateien auch eine große Anzahl von Datenblöcken verwalten, Inodes allerdings nur 15 Zeiger auf Datenblöcke speichern können, werden die Datenblöcke gestaffelt adressiert. Die Zeiger 1–12 verweisen direkt auf die entsprechenden Datenblöcke. Abhängig von der Blockgröße des Dateisystems (dazu weiter unten mehr) ist die Größe der durch diese direkte Adressierung speicherbare Datei stark begrenzt. Bei einer Standardblockgröße von 4 KByte können durch 13 Zeiger daher 13 × 4 KByte adressiert werden – keine große Ausbeute. Um größere Dateien adressieren zu können, verweisen die Zeiger 13–15 auf Datenblöcke, die selbst wiederum nur Verweise enthalten. Zeiger 13 verweist auf einen Datenblock, der Blocknummern weiterer Datenblöcke enthält. Zeiger 14 und 15 erhöhen diese Art des Verweises jeweils noch um eine weitere Ebene (siehe Abbildung 2.1). Die Größe der Datenblöcke kann beim Einrichten des Dateisystems (Formatieren) gewählt werden. ext3 erlaubt die Größen 1 KB, 2 KB und 4 KB. Aus dem Funktionsprinzip der Inodes und ihrer Adressierung von Datenblöcken ergibt sich, dass Dateien immer mindestens einen Datenblock belegen, auch wenn dieser nicht ganz ausgefüllt wird. Eine 1 KB große Datei belegt auf einer Partition mit 4 KB großen Datenblöcken 4 KB – genau einen Datenblock. Umgekehrt: Eine 4 KB große Datei belegt auf einem Dateisystem mit 1 KB großen Datenblöcken vier Blöcke. Im ersten Fall wird Platz verschwendet, im zweiten Fall ist erhöhter Verwaltungsaufwand notwendig, da vier Blöcke adressiert werden müssen. Lässt sich die Struktur der auf einer Partition zu speichernden Daten vor der Einrichtung eines Systems ermitteln, sollte die entsprechende Datenpartition an diese Struktur angepasst sein.
34
Einige Detailfragen
Zugriffsrechte Besitzer Gruppe Access Time Typ Größe
Datenblock
Linkzähler ... Pointer 0
Datenblock
Datenblock
Datenblock
... Pointer 11 Pointer 12 Pointer 13
Pointer 0
Pointer 0
Datenblock
...
...
Pointer 255
Pointer 255
Pointer 0
Pointer 0
...
...
Pointer 255
Pointer 255
Pointer 0
Pointer 0
Pointer 0
...
...
...
Pointer 255
Pointer 255
Pointer 255
Pointer 0
Pointer 0
...
...
Pointer 255
Pointer 255
Pointer 14 Datenblock
Pointer 0
Datenblock
Datenblock
Datenblock
... Pointer 255
Abbildung 2.1
Inode und Adressierung von Datenblöcken
Für einen Fileserver, auf dem ausschließlich große Multimediadateien abgelegt werden, ist ein Dateisystem mit möglichst großer Blockgröße ideal. Für einen Server, auf dem viele kleine Dateien abgelegt werden, sollte die Blockgröße möglichst klein gehalten werden. Die Blockgröße kann nachträglich nicht mehr geändert werden, weshalb dieser Aspekt vor Einrichtung des Servers betrachtet werden muss.
35
2.1
2
Installation und Konfiguration
Achten Sie darauf, dass Sie stets genügend Inodes zur Verfügung haben. Der Befehl df -i zeigt die belegten und verfügbaren Inodes der gemounteten Partitionen an: # df -i Dateisystem INodes /dev/sda3 2731008 varrun 224103 varlock 224103 procbususb 224103 udev 224103 devshm 224103 lrm 224103 2.6.22-14-generic/volatile
Selbst wenn noch ausreichend Platz auf einer Partition vorhanden ist, kann es vorkommen, dass keine Dateien mehr auf dieser Partition angelegt werden können, da alle Inodes belegt sind. Dies kann passieren, wenn mit vielen kleinen Dateien gearbeitet wird. Inodes repräsentieren Dateien, Dateien sind in Verzeichnissen geordnet, was ext3 in der Struktur des Dateisystems abbildet: Die zweite Datenstruktur nach den Inodes sind Verzeichniseinträge. Ein Verzeichniseintrag enthält den Namen der Dateien des betreffenden Verzeichnisses und die dazugehörigen Inodes. Damit lassen sich die Nutzdaten auf einer Festplatte effizient organisieren und darstellen. Inodes und Verzeichnisse werden in so genannten Blockgruppen organisiert. Dabei handelt es sich um Unterteilungen der Partition, mit denen Zugriffe optimiert werden, da Meta- und Nutzdaten physisch benachbart abgelegt sind, was den Zugriff auf diese Daten beschleunigt. Neben diesen Informationen, die ausschließlich die Speicherung von Daten im Dateisystem betreffen, müssen noch Informationen über das Dateisystem selbst abgelegt sein. Dies geschieht bei ext3 im so genannten Superblock. Der Superblock enthält alle relevanten Informationen über das Dateisystem. Diese umfassen unter anderem: 왘
Name der Partition
왘
Zeitpunkt des letzten Mountens
왘
Status des Dateisystems
왘
Zeitpunkt der letzten Prüfung
왘
Anzahl der freien Blöcke
36
Einige Detailfragen
왘
Adresse des ersten freien Blocks
왘
Angaben zu Größe und Anzahl der Inodes
왘
Informationen über reservierte Blöcke
왘
Größe des Journals
왘
etc.
Das Programm dumpe2fs gibt die im Superblock gespeicherten Angaben in einem lesbaren Format aus. Ohne Superblock ist das Dateisystem nicht benutzbar. Aufgrund seiner Wichtigkeit werden verschiedene Kopien des Superblocks an verschiedenen Stellen im Dateisystem abgelegt. Mit e2fsck -b kann bei der Prüfung eines Dateisystems ein alternativer Superblock angegeben werden für den Fall, dass der originäre Superblock defekt ist. Beim Anlegen eines neuen Dateisystems gibt mfks.ext3 an, wo sich Kopien des Superblocks befinden: # sudo mkfs.ext3 -L UMRK -b 4096 /dev/mapper/umrk mke2fs 1.40.2 (12-Jul-2007) Dateisystem-Label=UMRK OS-Typ: Linux Blockgröße=4096 (log=2) Fragmentgröße=4096 (log=2) 61063168 Inodes, 122095623 Blöcke 6104781 Blöcke (5.00 %) reserviert für den Superuser erster Datenblock=0 Maximum filesystem blocks=0 3727 Blockgruppen 32768 Blöcke pro Gruppe, 32768 Fragmente pro Gruppe 16384 Inodes pro Gruppe Superblock-Sicherungskopien gespeichert in den Blöcken: 32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208, 4096000, 7962624, 11239424, 20480000, 23887872, 71663616, 78675968, 102400000 Schreibe Inode-Tabellen: erledigt Erstelle Journal (32768 Blöcke): erledigt Schreibe Superblöcke und Dateisystem-Accountinginformationen: erledigt Das Dateisystem wird automatisch alle 27 Mounts bzw. alle 180 Tage überprüft, je nachdem, was zuerst eintritt. Veränderbar mit tune2fs -c oder -t .
37
2.1
2
Installation und Konfiguration
Da man sich in der Regel diese Angaben nicht merkt, können die Kopien des Superblocks im Problemfall mit dumpe2fs ermittelt werden: # sudo dumpe2fs /dev/mapper/umrk | grep -i super dumpe2fs 1.40.2 (12-Jul-2007) Filesystem features: has_journal resize_inode dir_ index filetype sparse_super large_file Primary Superblock in 0, Gruppendeskriptoren in 1-30 Backup Superblock in 32768, Gruppendeskriptoren in 32769-32798 Backup Superblock in 98304, Gruppendeskriptoren in 98305-98334 Backup Superblock in 163840, Gruppendeskriptoren in 163841-163870 Backup Superblock in 229376, Gruppendeskriptoren in 229377-229406 Backup Superblock in 294912, Gruppendeskriptoren in 294913-294942 Backup Superblock in 819200, Gruppendeskriptoren in 819201-819230 Backup Superblock in 884736, Gruppendeskriptoren in 884737-884766 Backup Superblock in 1605632, Gruppendeskriptoren in 1605633-1605662 Backup Superblock in 2654208, Gruppendeskriptoren in 2654209-2654238 Backup Superblock in 4096000, Gruppendeskriptoren in 4096001-4096030 Backup Superblock in 7962624, Gruppendeskriptoren in 7962625-7962654 Backup Superblock in 11239424, Gruppendeskriptoren in 11239425-11239454 Backup Superblock in 20480000, Gruppendeskriptoren in 20480001-20480030 Backup Superblock in 23887872, Gruppendeskriptoren in 23887873-23887902 Backup Superblock in 71663616, Gruppendeskriptoren in 71663617-71663646 Backup Superblock in 78675968, Gruppendeskriptoren in 78675969-78675998 Backup Superblock in 102400000, Gruppendeskriptoren in 102400001-102400030
Das Journal Wie bereits erwähnt, führt ext3 ein Journal über alle Dateisystem-Aktivitäten. Im Normalfall befindet sich das Journal auf derselben Partition wie das dazugehörige Dateisystem. Dies kann bei Systemen mit hohem I/O zu merkbaren Performanceproblemen führen, da für jeden Schreibvorgang nicht nur die entsprechenden Einträge in den Verwaltungsstrukturen (Inode, Verzeichnisse, Superblock) durchgeführt werden, sondern auch das Journal geschrieben werden muss. Abhilfe kann in solchen Fällen das Auslagern des Journals auf eine andere Festplatte bringen, so dass die Schreibvorgänge von Journal und Nutzdaten entkoppelt werden. In diesem Zusammenhang ist die Funktionsweise der Journalfunktion von ext3 interessant. Diese bietet drei Betriebsarten. Die Standardeinstellung ist der Ordered Mode. In dieser Betriebsart werden die zu schreibenden Nutzdaten erst auf den Datenträger und die Änderungen anschließend ins Journal geschrieben. Das bedeutet, dass ein Systemausfall während des Schreibvorgangs der Nutzdaten nicht zu einem inkonsistenten Dateisystem führt, da die Metadaten noch gar nicht aktualisiert worden sind. Die geschriebenen Nutzdaten sind schlicht unbrauchbar, beeinträch-
38
Einige Detailfragen
tigen aber die Integrität des Dateisystems nicht. Sofern keine besonderen Anforderungen an das Dateisystem bestehen, sollte der Ordered Mode die erste Wahl sein. Im Writeback Mode werden Änderungen am Dateisystem im Journal vermerkt und das Schreiben der Nutzdaten dem Kernel überlassen. Dieser schreibt die Daten dann zu einem geeigneten, aber beliebigen Zeitpunkt. Das kann dazu führen, dass das Journal geschrieben und Struktur und Metadaten des Dateisystems damit konsistent sind, die Nutzdaten, auf welche die betreffenden Inodes verweisen, aber noch gar keine sinnvollen Daten enthalten, da der Schreibvorgang durch den Kernel noch nicht durchgeführt worden ist. Der Nachteil liegt auf der Hand: Fällt zwischen dem Schreiben des Journals und dem Schreibvorgang des Kernels das System aus, ist das Dateisystem zwar konsistent, enthält aber in den noch nicht geschriebenen Datenblöcken nur Nonsens. Dieser Nachteil wird durch eine erhöhte Schreibgeschwindigkeit erkauft. Die dritte mögliche Betriebsart von ext3 ist der Full Mode. Dabei werden Metaund Nutzdaten ins Journal geschrieben und die Nutzdaten anschließend in die designierten Datenblöcke transferiert. Dieser Modus bietet höchstmögliche Datensicherheit, ist aufgrund des erhöhten Schreibaufkommens allerdings auch am langsamsten und sollte nur verwendet werden, wenn besondere Anforderungen an die Integrität des Dateisystems bestehen, für die der Ordered Mode nicht ausreichend wäre. In diesem Fall wäre das Auslagern des Journals auf eine zweite Festplatte sinnvoll, da allein durch die Betriebsart des Dateisystems sehr viel I/O entsteht. Fragmentierung Aus Struktur und Arbeitsweise des Dateisystems ergibt sich zwangsläufig das Problem der Fragmentierung. Jeder Anwender von Desktopsystemen kennt dieses Phänomen, wird doch insbesondere in der Windows-Welt darum häufig viel Aufheben gemacht. Fragmentierung bedeutet, dass zu einer einzigen Datei gehörende Nutzdaten auf einer Partition nicht an einem Stück – in aufeinander folgenden Blöcken – gespeichert werden, sondern über die Partition verteilt. Dieser Umstand tritt entweder dann ein, wenn für das Speichern einer Datei nicht mehr ausreichend viele zusammenhängende Blöcke verfügbar sind oder wenn eine bereits geschriebene Datei geändert wird und die Änderung an eine andere Stelle geschrieben wird, da hinter den bereits angelegten Datenblöcken kein freier Block mehr verfügbar ist. Der erste Fall tritt insbesondere dann auf, wenn die Partition stark gefüllt ist, weswegen Fragmentierung häufig als Problem übervoller Festplatten beschrieben wird. Dies ist allerdings nur teilweise richtig, da der zweite Fall, Fragmentierung durch nachträgliche Änderung von Dateien, unab-
39
2.1
2
Installation und Konfiguration
hängig vom Füllgrad einer Partition ist und durch normale Benutzung entsteht. Je mehr Schreibvorgänge auf einer Partition stattfinden, desto stärker ist zwangsläufig die Fragmentierung. Um der Fragmentierung präventiv zu begegnen, reserviert ext3 beim Anlegen einer Datei immer acht zusammenhängende Datenblöcke – sofern möglich. Bewegen sich die Änderungen an einer Datei innerhalb dieser reservierten Größe, fragmentiert die Datei nicht. Erst wenn neue Blocks angefordert werden und diese Blocks an einer anderen Stelle im Dateisystem liegen, wird die Datei fragmentiert. Fragmentierung hängt daher neben dem Füllstand einer Partition auch von der Größe der hauptsächlich vorhandenen Dateien ab. Fragmentierung lässt sich nicht vermeiden und findet bei der Verwendung von Dateisystemen unweigerlich statt. Leider wird sie nach wie vor häufig überbewertet. Der Grund mag darin liegen, dass Fragmentierung in den Zeiten von Single-User-Betriebssystemen wie MS-DOS ein für den Anwender merkliches Problem dargestellt hat. Zum einen waren Festplatten damals noch deutlich langsamer als heutzutage, zum anderen greifen bei einem Single-User-Betriebssystem auch nicht verschiedene Prozesse gleichzeitig auf das Dateisystem zu. Bei Linux als Multiuser- und Multitasking-Betriebssystem sind die Schreib/Leseköpfe der Festplatte ständig in Bewegung, Fragmentierung fällt daher wesentlich weniger ins Gewicht. Überdies werden Daten in einer ext3-Partition nicht durchgängig sequentiell abgelegt, sondern in den oben beschriebenen Blockgruppen, weswegen die Festplatte ohnehin nicht rein sequentiell arbeiten kann. Bei normaler Anwendung ist Fragmentierung daher überhaupt nicht bemerkbar. Das Thema sollte folglich nicht überbewertet werden. Dass es auch von der Linux-Community nicht als ernstes Thema betrachtet wird, zeigt die Tatsache, dass es kein Defragmentierungstool für ext3 gibt. Die einzige Möglichkeit, eine Partition zu defragmentieren, besteht darin, ihren Inhalt auf eine andere Partition zu kopieren, alle Daten der ursprünglichen Partition zu löschen und die Daten dann wieder auf die Partition zu kopieren. ext3-Tools Die folgende Tabelle zeigt die wichtigsten Programme für die Arbeit mit ext3 und ext2 (enthalten im Paket e2fsprogs). Bitte beachten Sie, dass das Verwenden dieser Tools grundsätzlich nur auf nicht gemounteten Partitionen erfolgen sollte! Selbst das Überprüfen eines Dateisystems mit e2fsck kann irreparable Schäden hinterlassen, wenn das überprüfte Dateisystem noch gemounted ist.
40
Einige Detailfragen
Programm
Funktion
e2fsck
Überprüfen eines mit ext2 oder ext3 formatierten Dateisystems. e2fsck -b <SUPERBLOCK> verwendet einen alternativen Superblock, falls der erste Superblock defekt ist.
fsck.ext2
Entspricht e2fsck.
fsck.ext3
Entspricht e2fsck.
debugfs
Interaktive Debugger zur Analyse eines ext2/ext3-Dateisystems.
mke2fs
Erstellt ein ext2/ext3-Dateisystem.
badblocks
Programm zur Suche nach defekten Blöcken. Bei der Verwendung der Ergebnisse mit e2fsck ist es wichtig, die korrekte Blockgröße zu beachten.
tune2fs
Ändern von Eigenschaften des Dateisystems wie z. B. Anzahl von Mounts bis zur automatischen Überprüfung, Einstellung des JournalModus, Bezeichner des Dateisystems etc.
dumpe2fs
Gibt Informationen über ein ext2/ext3-Dateisystem aus.
blkid
Ausgabe von Attributen eines ext2/ext3-Dateisystems.
e2image
Speichert Metadaten eines ext2/ext3-Dateisystems in einer Datei. Die Ausgabe kann mit dumpe2fs oder debugfs analysiert werden.
mkfs.ext2
Entspricht mke2fs.
mkfs.ext3
Entspricht mke2fs.
e2label
Ändert das Label (Bezeichner) eines Dateisystems.
findfs
Sucht auf einem Blockdevice nach einem als Kommandozeilenparameter spezifizierten Dateisystem.
resize
Ändern der Größe eines Dateisystems. Wichtig: Es wird nur die Größe des Dateisystems geändert, nicht die der Partition, auf der sich das Dateisystem befindet.
mklost+found
Erzeugt ein lost+found-Verzeichnis in einem Dateisystem. Das lost+ found-Verzeichnis wird zur Ablage von im Rahmen einer Dateisystemüberprüfung wiederhergestellten Blöcken verwendet. Durch das Erzeugen dieses Verzeichnisses werden bereits Blöcke im Dateisystem reserviert.
filefrag
Gibt Angaben über die Fragementierung einer Datei aus.
Tabelle 2.2
2.1.3
Die wichtigsten Programme für das ext2/ext3-Dateisystem
RAID
Festplatten enthalten mechanische Bauteile und unterliegen daher einem Verschleißprozess. Die Hersteller von Festplatten geben zwar Werte wie MTBF (Mean Time Between Failures) an, mit denen die statistische Wahrscheinlichkeit des Defektes einer Festplatte errechnet werden soll, aber leider halten sich technische Geräte selten an statistische Vorhersagen und gehen immer zum ungüns-
41
2.1
2
Installation und Konfiguration
tigsten Zeitpunkt kaputt. Präventive Maßnahmen wie ein regelmäßiges Backup helfen im Fall eines Festplattenausfalls zwar bei der Wiederherstellung eines Systems, bis diese Wiederherstellung abgeschlossen ist, ist das betroffene System allerdings nicht verfügbar. Bei Systemen mit besonderen Ansprüchen an die Verfügbarkeit hilft ein Backup allein also nicht. Um ein System ausfallsicher(er) zu machen, ist der Einsatz eines RAID-Systems ratsam. Als RAID wird der Zusammenschluss verschiedener Festplatten zu einem logischen Verbund bezeichnet. Für den Benutzer eines Betriebssystems erscheint dieser Verbund als normale Festplatte, das Betriebssystem, bzw. der RAID-Controller sorgen im Hintergrund dafür, dass die Daten auf die verschiedenen Festplatten verteilt werden. RAID-Systeme gibt es in zwei Versionen, dem Hardware-RAID, bei dem ein spezieller Controller zur Verwaltung des RAIDs verwendet wird, und dem SoftwareRAID, bei dem die Verwaltung des RAIDs durch das jeweilige Betriebssystem, in unserem Fall Linux, übernommen wird. Der Controller des Hardware-RAIDs erstellt aus den physischen Festplatten das logische Laufwerk. Das Betriebssystem selbst sieht nur dieses logische Laufwerk und hat daher keine Kenntnis darüber, dass im Hintergrund ein RAID seinen Dienst verrichtet. Der Vorteil bei dieser Art des RAIDs ist die hohe Performance, die durch den Einsatz eines entsprechend optimierten Controllers erzielt werden kann. Dieser übernimmt alle für den Betrieb des RAIDs notwendigen Verwaltungsaufgaben. Überdies sind hochwertige Controller mit einer Caching-Funktionalität ausgestattet, was den Zugriff auf die Daten enorm beschleunigen kann. Der Vorteil des Software-RAIDs besteht in seiner Einfachheit. Man benötigt lediglich die entsprechende Anzahl von Festplatten und richtet das RAID im Betriebssystem ein. Die Zusatzkosten durch die Anschaffung eines RAID-Controllers entfallen. Allerdings wird diese Einfachheit dadurch erkauft, dass die Verwaltung des RAIDs Performance des Systems benötigt und keine Möglichkeit der Optimierung bietet wie z. B. ein RAID-Controller mit Caching-Funktionalität. Auch kann ein Software-Fehler dazu führen, dass die Verwaltung des RAIDs aus dem Tritt kommt und sich die im RAID gespeicherten Daten in Datenmüll verwandeln. RAID 0 RAID-Systeme dienen nicht nur der Erhöhung der Ausfallsicherheit. In Abhängigkeit von der Anordnung der Festplatten im RAID kann ein RAID auch dazu benutzt werden, durch Verteilung von Daten auf mehrere physische Datenträger eine höhere Performance zu erzielen. Dieses Verfahren wird als RAID 0 oder Striping bezeichnet. Dabei wird ein logisches Laufwerk über zwei oder mehr physische Datenträger verteilt. Zugriffe auf die Daten verteilen sich dann auf die ver-
42
Einige Detailfragen
schiedenen Datenträger, so dass jeder Datenträger nur mit 1/n Operationen belastet wird (n entspricht der Anzahl der Festplatten im RAID-Verbund). Darüber hinaus ermöglicht RAID 0 das Anlegen großer Partitionen, denn der Gesamtspeicherplatz des RAID-Verbundes entspricht der Summe der Einzelkapazitäten der physischen Datenträger. Die Vorteile des RAID 0 werden allerdings durch eine erhöhte Ausfallwahrscheinlichkeit erkauft. Fällt in einem RAID-0-Verbund ein Datenträger aus, sind alle Daten im Verbund unbrauchbar. RAID 0 sollte daher nur in Ausnahmefällen zum Einsatz kommen. RAID 1 Die einfachste Art eines RAIDs zur Erhöhung der Ausfallsicherheit ist RAID 1, das so genannte Mirroring. Dabei werden mindestens zwei physische Datenträger gespiegelt, d. h., jeder physische Datenträger enthält einen kompletten Satz aller Daten. Fällt ein Datenträger im Verbund aus, so kann der verbleibende Datenträger die Funktionsfähigkeit aufrechterhalten. Bei hotplugfähiger Hardware wird der defekte Datenträger im laufenden Betrieb gegen einen neuen Datenträger ausgetauscht, und der RAID-Controller bzw. das Software-RAID erstellt auf dem neuen Datenträger einen neuen Spiegel der Daten. Dieser RAID-Modus ist der sicherste, hat allerdings den größten Platzverbrauch – die Gesamtkapazität des RAID-Verbundes entspricht der Einzelkapazität des kleinsten Datenträgers. Des Weiteren bietet dieser Modus keinen Geschwindigkeitsvorteil gegenüber dem Einsatz einer einzelnen Festplatte ohne RAID-Funktionalität. Aufgrund seiner einfachen Struktur und der geringen Anforderungen (es werden nur zwei Festplatten benötigt), stellt RAID 1 im privaten und semiprofessionellen Umfeld sicher die beste Wahl dar. RAID 5 Bei RAID 5 werden mindestens drei Festplatten zu einem Verbund zusammengeschlossen. Die Daten werden über alle drei Festplatten verteilt, allerdings werden zu den gespeicherten Daten auf den jeweils anderen Datenträgern Paritätsinformationen abgelegt, mit denen beim Ausfall eines Datenträgers die auf diesem Datenträger befindlichen Daten wiederhergestellt werden können. RAID 5 verbindet auf diese Weise einen Geschwindigkeitsvorteil durch die Verteilung von Daten auf mehrere Datenträger mit der Sicherheit eines RAID 1. Die Kapazität eines RAID-5-Verbundes entspricht der Kapazität der kleinsten verwendeten Festplatte im Verbund multipliziert mit der Anzahl der Festplatten minus 1.
43
2.1
2
Installation und Konfiguration
RAID 10 RAID 5 stellt einen guten Kompromiss zwischen Geschwindigkeit und Datensicherheit dar. Reicht dieser Kompromiss nicht aus, kann RAID 10 helfen. RAID 10 ist ein gespiegeltes RAID 0, verbindet also die Performance eines RAID 0 mit der Sicherheit eines RAID 1. Für ein RAID 10 werden folglich mindestens vier Festplatten benötigt. Die Gesamtkapazität entspricht der Hälfte der Summe der Einzelkapazitäten aller Datenträger.
2.2
Installation
Die folgenden Abschnitte beschreiben die Installation von Gentoo und Ubuntu. Beide Vorgänge sind in einzelne Unterabschnitte aufgeteilt, da sich die Installationen beider Distributionen aufgrund der verschiedenen Konzepte stark unterscheiden.
2.2.1
Gentoo
Für die Installation von Gentoo ist es empfehlenswert, das Gentoo-Handbuch1 geöffnet zu haben und der Anleitung zu folgen. Im Folgenden werden die wichtigsten Schritte aufgeführt, für eine detaillierte Beschreibung ziehen Sie bitte das Handbuch zu Rate. Der erste Schritt besteht im Download der Gentoo-Live-CD. Diese erhält man bei einem der zahlreichen Gentoo-Mirrors: http://www.gentoo.org/main/en/mirrors2.xml Das Gentoo-Handbuch empfiehlt die Überprüfung der heruntergeladenen Datei mit Hilfe der auf dem Downloadserver angegebenen Hash-Prüfsummen oder per GPG. Welchen Nutzen Prüfsummen haben sollen, die sich auf demselben System wie die zu prüfenden Daten befinden, ist allerdings reichlich fragwürdig. Ein Angreifer, der einen Downloadserver kompromittieren kann, kann ohne weiteres Daten auf diesem Server verändern, das schließt Nutzdaten und deren Prüfsummen mit ein. Sinnvoll ist einzig die Angabe der Prüfsummen auf getrennten Servern, so wie es z. B. das Apache-Projekt macht. Obendrein sind die angebotenen Hash-Verfahren MD5 und SHA1 nicht mehr zeitgemäß. Betrachten Sie die HashWerte daher nicht als Sicherheitsgarantie. Mittlerweile ist für Gentoo eine Live-CD verfügbar, die einen grafischen Installer mitbringt. Dieser ist zwar sehr bunt und gaukelt eine zeitgemäße Benutzerober1 http://www.gentoo.org/doc/de/handbook/handbook-x86.xml
44
Installation
fläche vor, ist aber in der Praxis kaum zu gebrauchen. Die Bedienung ist umständlich, und das Programm ist instabil. Die Empfehlung geht daher klar zum Konsolen-Installer. Dieser ist nicht ganz so bunt, lässt dem Benutzer aber alle benötigten Freiräume und führt die Installation zuverlässig aus. Beide Installer-Varianten sind über die entsprechenden Icons auf dem Desktop des über die Live-CD gestarteten Systems zu erreichen. Die Live-CD bringt einen Portage-Snapshot mit, aus dem das Basissystem erstellt wird, kann also auch ohne Internetanbindung installiert werden. Wird eine Minimal-CD verwendet, muss der Snapshot aus dem Internet nachgeladen werden. Portage ist der Paketmanager von Gentoo; der Portage-Snapshot stellt die Grundlage der folgenden Installation dar. Am Anfang der Installation steht die Partitionierung der Festplatte, die nach Lektüre des Abschnitts 2.1.1 kein grundsätzliches Problem darstellen sollte. Der wichtigste Schritt nach der Partitionierung der Festplatte ist das Festlegen der Compiler-Optionen (CFLAGS). Weil das komplette Betriebssystem aus dem Quelltext übersetzt wird, ist das korrekte Festlegen dieser Optionen von großer Wichtigkeit, da der Compiler nur mit den richtigen Optionen optimal für die vorhandene Hardware Programme erzeugen kann. Bei den CFLAGS muss der korrekte Prozessor angegeben werden. Der Installer schlägt meistens i686 vor, was aber nur eine generische Angabe ist und keine spezielle Optimierung des Compilers für den wirklich verwendeten Prozessor ermöglicht. Wenn Sie unsicher sind, welcher Prozessor in Ihrem Rechner steckt, öffnen Sie ein Terminal und fragen Linux nach dem Prozessor: # cat /proc/cpuinfo processor : 0 vendor_id : GenuineIntel cpu family : 6 model : 13 model name : Intel(R) Pentium(R) M processor 1.86GHz stepping : 8 cpu MHz : 800.000 cache size : 2048 KB fdiv_bug : no hlt_bug : no f00f_bug : no coma_bug : no fpu : yes fpu_exception : yes cpuid level : 2 wp : yes
45
2.2
2
Installation und Konfiguration
flags
bogomips clflush size
: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat clflush dts acpi mmx fxsr sse sse2 ss tm pbe up est tm2 : 1598.37 : 64
Im diesem Fall liegt ein Pentium M vor, weswegen in der Installer-Oberfläche dieser Prozessortyp ausgewählt ist. Den Optimierungslevel des Compilers (»Optimizations«) sollten Sie auf der Voreinstellung -O2 belassen, es sei denn, Sie wissen, was Sie tun. Zu Risiken und Nebenwirkungen von zu großer Compiler-Optimierung befragen Sie bitte die Manpage des gcc. Für die restlichen CFLAGS gilt prinzipiell dasselbe. Falls Ihnen nach längerem Betrieb von Gentoo neue Optimierungsmöglichkeiten durch entsprechende CFLAGS einfallen, können Sie das System einfach komplett neu übersetzen lassen; während der Installation vorgenommene Einstellungen sind jederzeit änderbar. Eine weitere Besonderheit, um die es sich an dieser Stelle zu kümmern gilt, sind die so genannten USE-Flags. Mit den USE-Flags wird dem System mitgeteilt, welche besonderen Fähigkeiten die zu übersetzenden Applikationen besitzen sollen. Sollen Applikationen beispielsweise Unterstützung für Sound haben, muss das USE-Flag alsa gesetzt sein, für Gnome-Unterstützung gnome etc. Auch hier gilt: Wenn zur Installationszeit noch nicht feststeht, ob ein bestimmtes USE-Flag benötigt wird, sollte es im Zweifelsfall weggelassen werden. Im Nachhinein können USE-Flags jederzeit geändert werden – Applikationen, die von den Änderungen profitieren sollen, müssen dann lediglich neu übersetzt werden. Gentoo unterscheidet zwischen globalen USE-Flags, die alle Applikationen betreffen, und lokalen USE-Flags, die nur die Applikationen betreffen, denen diese USE-Flags zugeordnet sind. Im weiteren Verlauf des Buches wird die Arbeit mit USE-Flags noch näher erläutert werden. Ein bei der Installation zu beachtender wichtiger Punkt ist die Auswahl der optional zu installierenden Pakete. Abhängig davon, wie umfangreich diese Pakete sind, kann sich die Installation ab diesem Zeitpunkt enorm in die Länge ziehen, da das Übersetzen umfangreicher Pakete wie KDE oder Gnome auch auf aktuellen Rechnern recht zeitintensiv ist. Bedenken Sie bei der Auswahl der optionalen Pakete, dass Sie einen Server einrichten möchten, und auf einem Server sollte aus Sicherheitsgründen grundsätzlich nur wirklich benötigte Software vorhanden sein. Im Anschluss an die Installation gibt es einige Grundeinstellungen vorzunehmen, bevor das System mit Diensten versehen oder für den Produktivbetrieb gehärtet werden kann. Das Härten ist Gegenstand von Kapitel 3, »Systemhärtung«, die Grundkonfiguration wird in Abschnitt 2.3 beschrieben.
46
Installation
2.2.2
Ubuntu
Ubuntu kann von der Website www.ubuntu.com oder einem der zahlreichen Mirror-Servern als ISO-Image heruntergeladen werden. Wie bei Gentoo sind auf den Downloadservern Dateien mit Hashwerten der herunterladbaren ISO-Dateien verfügbar. Allerdings gibt es darüber hinaus noch eine zentrale Webseite, auf denen die Hash-Werte aller Ubuntu-Versionen aufgeführt sind: https://help.ubuntu.com/community/UbuntuHashes Da diese Webseite technisch von den verschiedenen Downloadservern getrennt ist, kann auf diese Weise eine zuverlässige Überprüfung der ISO-Dateien durchgeführt werden. Es ist eher unwahrscheinlich, wenngleich nicht unmöglich, dass ein Angreifer den oder die zentralen Ubuntu-Server und die Downloadserver gleichzeitig kompromittiert und Daten samt Hash-Wertdateien verändert. Praktischerweise sind die auf den Downloadservern vorhandenen Hash-Wertdateien mit GPG signiert. Unpraktischerweise sind zur Zeit der Manuskripterstellung die von Ubuntu zur Unterschrift verwendeten GPG-Schlüssel nicht mehr gültig: # gpg -v MD5SUMS.gpg gpg: ASCII-Hülle: Version: GnuPG v1.4.3 (GNU/Linux) Abgetrennte Beglaubigungen. Bitte geben Sie den Namen der Datendatei ein: MD5SUMS gpg: Signatur am Fr 18 Apr 2008 13:21:34 CEST mit DSA Schlüssel, ID FBB75451, erfolgt gpg: Schlüssel FBB75451 von hkp Server subkeys.pgp.net anfordern gpg: ASCII-Hülle: Version: SKS 1.0.10 gpg: pub 1024D/FBB75451 2004-1230 Ubuntu CD Image Automatic Signing Key gpg: verwende Vertrauensmodell classic gpg: Schlüssel FBB75451: Öffentlicher Schlüssel "Ubuntu CD Image Automatic Signing Key " importiert gpg: 53 keys cached (485 signatures) gpg: 9 Schlüssel verarbeitet (11 Validity Zähler gelöscht) gpg: 3 marginal-needed, 1 complete-needed, classic Vertrauensmodell gpg: HINWEIS: Beglaubigungsschlüssel 0324204A ist am Do 08 Feb 2007 23:17:56 CET verfallen gpg: HINWEIS: Beglaubigungsschlüssel B7E1CB64 ist am Mo 11 Feb 2008 17:18:31 CET verfallen gpg: Tiefe: 0 gültig: 2 signiert: 6 Vertrauen: 0-, 0q, 0n, 0m, 0f, 2u gpg: Tiefe: 1 gültig: 6 signiert: 0 Vertrauen: 6-, 0q, 0n, 0m, 0f, 0u
47
2.2
2
Installation und Konfiguration
gpg: nächste "Trust-DB"-Pflichtüberprüfung am 2009-03-10 gpg: Anzahl insgesamt bearbeiteter Schlüssel: 1 gpg: importiert: 1 gpg: Korrekte Unterschrift von 'Ubuntu CD Image Automatic Signing Key ' gpg: WARNUNG: Dieser Schlüssel trägt keine vertrauenswürdige Signatur! gpg: Es gibt keinen Hinweis, daß die Signatur wirklich dem vorgeblichen Besitzer gehört. Haupt-Fingerabdruck = C598 6B4F 1257 FFA8 6632 CBA7 4618 1433 FBB7 5451 gpg: Binäre Unterschrift, Hashmethode "SHA1"
Obendrein gibt es in einem Web-of-Trust-basierten Kryptosystem wie GPG keine Möglichkeit, die Identität eines Kommunikationspartners zweifelsfrei zu überprüfen. Insofern stellt die GPG-Signatur auch keine 100 %ige Sicherheit dar. Da es aber keine andere Möglichkeit gibt, die Integrität der Software zu überprüfen, müssen die vorhandenen Mittel als ausreichend angesehen werden. Um die Integrität der heruntergeladenen Datei mit den Werten auf der Ubuntu-Hash-SumSeite zu vergleichen, erstellen Sie mit dem Programm die Hash-Summe der heruntergeladenen Datei und vergleichen diese mit dem entsprechenden Wert auf der Webseite: # md5sum ubuntu-8.04-server-i386.iso c3162b21757746c64a0a22cdd060b164ubuntu-8.04-server-i386.iso
Nach Durchlaufen aller Installationsschritte ist das Grundsystem installiert und kann konfiguriert werden. Ubuntu: Alternate-Version Neben der Server- und der Desktopvariante bietet Ubuntu noch eine so genannte Alternate-Version an. Diese Version verfügt über erweiterte Installationsmöglichkeiten und erlaubt beispielsweise die Installation auf dem LVM-Volume sowie das Verschlüsseln der gesamten Festplatte mit dm_crypt. Das manuelle Einrichten und Verwenden von LVM wird in diesem Kapitel erläutert, weshalb auf die Verwendung der Alternate-CD an dieser Stelle verzichtet wird.
2.3
Feintuning
Bevor ein System in den Produktivbetrieb übergehen kann, steht noch einiges an Konfigurationsarbeit an. Das Einrichten von Paketmanager und Administrationszugängen sowie die Härtung des Systems sind einige der wichtigsten Tätigkeiten.
48
Feintuning
2.3.1
Paketmanagement einrichten
Die Netzwerkfunktionalität wird bei Gentoo und Ubuntu bereits im Verlauf der Installation eingerichtet, so dass im Anschluss an die Installation ein lauffähiges System mit Internetanbindung vorhanden sein sollte. Der erste Schritt zur fertigen Konfiguration nach der Installation ist das Einrichten des Paketmanagers. Ubuntu: APT Grundlage der Paketverwaltung von Ubuntu ist das Advanced Packaging Tool (APT), das mit Paketen im Debian-Format arbeitet (deb). APT stammt von Debian und verwendet das Debian-Paketformat für Softwarepakete. Bei den Desktopversionen von Ubuntu ist die Paketverwaltung in grafische Oberflächen wie Synaptic gekapselt. Bei der Serverversion von Ubuntu muss der Administrator mangels einer grafischen Oberfläche auf die Kommandozeile zurückgreifen. Die Schnittstelle zu APT stellt hierbei das Programm apt-get dar, mit dem alle wichtigen Aktionen des Paketmanagements durchgeführt werden können: 왘
Pakete installieren
왘
Pakete löschen
왘
Paketquellen aktualisieren
왘
Updates installieren
왘
etc.
Informatiker-Humor Ubuntu ist dem alten Witz von Debian treu geblieben und bietet bei APT immer noch den Kommandozeilenparameter moo an: # apt-get moo (__) (oo) /------\/ / | || * /\---/\ ~~ ~~ ...."Have you mooed today?"...
Damit sollte auch klar sein, warum apt-get – ohne Parameter aufgerufen – den Satz »This APT has Super Cow Powers.« ausgibt.
APT wird über die Datei /etc/apt/sources.list konfiguriert. In dieser Datei werden die Quellen festgelegt, an denen APT nach Software sucht. Um die vorzunehmenden Einstellungen zu verstehen, ist es sinnvoll, die Struktur des Ubuntu-Softwarearchivs zu betrachten.
49
2.3
2
Installation und Konfiguration
Für die Installation neuer Programme oder von Updates bietet Ubuntu sechs verschiedene Archive für Software an, die auf den Downloadservern in unterschiedliche Verzeichnisse aufgeteilt sind. Diese Archive teilen die vorhandene Software nach technischen Gesichtspunkten auf.
Abbildung 2.2 Die Ubuntu-Archive
Das Archiv mit dem Namen der jeweiligen Distribution (Gutsy, Hardy etc.) stellt den Entwicklungsstand zum Zeitpunkt der Veröffentlichung der jeweiligen Distribution dar. Nach der Veröffentlichung bleibt dieses Archiv unverändert. Das Archiv mit dem Zusatz backports enthält Programme, die in der darin enthaltenen Version in der betreffenden Distribution zum Veröffentlichungszeitraum nicht enthalten waren, zur Benutzung aber von der aktuell in der Entwicklung befindlichen Distribution zurückportiert worden sind. Falls Sie Software in einer Version benötigen, die in der von Ihnen verwendeten Distribution noch nicht ver-
50
Feintuning
fügbar ist, sollten Sie prüfen, ob die Software in backports bereits vorhanden ist. Beachten Sie dabei bitte, dass zurückportierte Software möglicherweise nicht ideal mit dem System zusammenarbeitet und Instabilitäten oder andere Probleme verursachen kann. Für ein Produktivsystem sollten Sie daher von backports absehen. Im Archiv updates befinden sich überarbeitete Pakete, bei denen kleine Fehler behoben wurden, die aber nicht sicherheitskritisch sind. Die Installation aus Sicherheitsgründen ist daher optional. Das Archiv proposed enthält Software, die für eine Aufnahme in das Archiv updates vorgesehen ist, für den Produktivbetrieb aber noch nicht ausreichend getestet wurde. Für ein Produktivsystem ist die Verwendung von proposed daher nicht empfehlenswert. Warten Sie lieber, bis die betreffende Software von proposed zu updates gewandert ist. Sicherheitsaktualisierungen werden im Archiv security abgelegt. Das bedeutet, dass dieses Archiv unbedingt in die Paketverwaltung mit einbezogen werden muss, um ein System sicherheitstechnisch auf aktuellem Stand zu halten. Das letzte Archiv ist commercial. Hier liegt – wie der Name bereits vermuten lässt – kommerzielle Software in Binärform, ohne den dazugehörigen Quelltext. Seit Gutsy ist das commercial-Archiv in der partner-Komponente aufgegangen. Damit hat Ubuntu eine logische Inkonsistenz in der Aufteilung zwischen Archiven und Komponenten beseitigt, denn während die fünf obengenannten Archive die Software nach ihrem Entwicklungsstand einteilen, ist die Einteilung anhand der Quelloffenheit ein nicht-technisches Kriterium. Diese Unterscheidung wird aber nicht durch die Archive, sondern durch die nachfolgend beschriebenen Komponenten vorgenommen. Während die Archive Software nach ihrem Entwicklungsstand aufteilen, werden Komponenten dazu verwendet, Software anhand von »Meta-Eigenschaften« zu klassifizieren. Ubuntu kennt fünf Komponenten: 왘
Main: Vom Ubuntu-Team unterstützte und gepflegte Software.
왘
Restricted: Für den Betrieb des Systems wichtige Software, die aufgrund fehlender Quelloffenheit vom Ubuntu-Team nur sehr eingeschränkt unterstützt werden kann.
왘
Universe: Beliebige freie Software, die über APT installiert werden kann, vom Ubuntu-Team aber nicht unterstützt wird.
왘
Multiverse: Entspricht der Universe-Komponente, allerdings unterliegt die Software lizenzrechtlichen Einschränkungen.
왘
Partner: Software, die nur in Binärform vorliegt (Closed Source).
51
2.3
2
Installation und Konfiguration
Mit diesen Informationen ist der Inhalt der Datei /etc/apt/sources.list weitestgehend selbsterklärend. Die Zeile … deb http://de.archive.ubuntu.com/ubuntu/ hardy main restricted
… legt beispielsweise fest, dass APT auf dem Server de.archive.ubuntu.com in den Komponenten main und restricted nach Software für Hardy (8.04) sucht. Da eine Distribution ohne Updates schnell veraltet und nicht mit Sicherheitsupdates versorgt wird, muss eine Quelle für Updates eingetragen werden: deb http://de.archive.ubuntu.com/ubuntu/ hardy-updates main restricted
Die Konfiguration von universe- oder multiverse-Komponenten erfolgt analog: deb http://de.archive.ubuntu.com/ubuntu/ hardy multiverse deb http://de.archive.ubuntu.com/ubuntu/ hardy universe
Eine Besonderheit stellen die Zeilen dar, die mit deb-src beginnen. Mit diesen Einträgen werden Quellen für Quelltextpakete angegeben. Dies ist für Benutzer von Interesse, die Programme selbst kompilieren möchten oder aus anderen Gründen Zugriff auf den Quelltext der installierten Software benötigen. Als Server kann ein beliebiger Ubuntu-Mirror eingetragen werden, der die entsprechenden Pakete bereitstellt. Die Quellen für Ihr Ubuntu-System können frei konfiguriert werden. Auf backports und proposed sollte für einen produktiven Server verzichtet werden. Ob universe, multiverse, restricted oder partner als Komponenten ausgewählt werden, hängt von den konkreten Anforderungen an den Server ab. Um Quellen und System übersichtlich zu halten, sollten so wenig Archive und Komponenten wie möglich ausgewählt werden. Nach der Konfiguration von /etc/apt/sources.list muss der Benutzer mit dem Befehl … apt-get update
… die neuen Quellen einlesen. Dabei erstellt APT eine Liste der auf den eingetragenen Quellen verfügbaren Software. Die Listen werden im Verzeichnis … /var/lib/apt/lists
… abgelegt. Für jedes Paket sind Prüfsummen hinterlegt (MD5, SHA-1 und SHA256), mit denen die Integrität der Pakete nach dem Download überprüft wird. Mit dem Befehl … apt-cache search <package>
… können die Paketlisten mit einem regulären Ausdruck durchsucht werden. Dies ist insbesondere dann nützlich, wenn Softwarepakete gesucht werden,
52
Feintuning
deren Namen man nicht kennt. Ohne weiteren Parameter aufgerufen, durchsucht apt-cache die gesamte Paketbeschreibung. Das kann zu langen Ergebnislisten führen. Die Suche nach dem Ausdruck »thunderbird« beispielsweise führt zu einer Liste mit 70 Ergebniseinträgen: # apt-cache search thunderbird | wc -l 70
In der Ergebnisliste sind alle Pakete aufgeführt, bei denen der Ausdruck »thunderbird« im Namen oder in der Paketbeschreibung enthalten ist. Bei der Suche nach dem Programm Thunderbird ist diese Ergebnisliste nur sehr eingeschränkt nützlich. apt-cache kennt daher den Parameter --names-only, mit dem die Suche auf die Paketnamen beschränkt wird: # apt-cache -n search thunderbird | wc -l 42
Die Ergebnisliste ist immer noch umfangreich, was daran liegt, dass der als Suchparameter übergebene reguläre Ausdruck in einem Paketnamen enthalten sein muss, diesem aber nicht exakt zu entsprechen braucht. Es wurden daher alle Pakete gefunden, deren Name den Ausdruck »thunderbird« enthält. Um gezielt nach dem Paket »thunderbird« zu suchen, muss der reguläre Ausdruck entsprechend spezifiziert werden: # apt-cache -n search ^thunderbird$ thunderbird - mail/ news client with RSS and integrated spam filter support
Voilà, durch Kombination der Parameter von apt-cache und der Syntax regulärer Ausdrücke wird apt-cache zu einem mächtigen Werkzeug. Reguläre Ausdrücke sind eine eigene Disziplin der Informatik und können daher in diesem Buch nicht detailliert behandelt werden. Das Standardwerk zu regulären Ausdrücken ist das Buch »Mastering Regular Expressions« von Jeffrey Friedl. Nach der erfolgreichen Konfiguration von APT und dem Einlesen der Paketlisten von den neu eingetragenen Quellen kann das System nun über das Programm apt-get mit neuen Paketen versorgt werden. Zur Installation übernimmt aptget dabei den Parameter install, gefolgt vom Paketnamen des zu installierenden Paketes. Um das vorstehend über apt-cache ermittelte Thunderbird zu installieren, lautet der Befehl: apt-get install thunderbird apt-get lädt das Paket von der entsprechenden Quelle und installiert es anschlie-
ßend automatisch.
53
2.3
2
Installation und Konfiguration
Ein installiertes Paket wird mit dem Befehl ... apt-get remove <paketname>
... gelöscht. Sollen auch zu diesem Paket gehörende Konfigurationsdateien gelöscht werden, muss das Paket »gepurged« werden: apt-get purge <paketname>
Die folgende Tabelle beschreibt die wichtigsten Parameter von apt-get: Befehl
Zweck
update
Liest die Paketlisten ein, die in den in der Datei /etc/apt/sources.list konfigurierten Quellen verfügbar sind.
upgrade
Installiert die neusten verfügbaren Paketversionen.
dist-upgrade
Führt ein Distributionsupgrade durch, beispielsweise von Gutsy (7.10) zu Hardy (8.04). Diese Funktion ist mit Vorsicht zu genießen. Ein vorheriges Backup wird wärmstens empfohlen!
install
Installiert das angegebene Paket.
remove
Löscht das angegebene Paket.
purge
Löscht das angegebene Paket und entfernt alle zugehörigen Konfigurationsdateien.
source
Lädt die Quelltextdateien zum angegebenen Paket von der entsprechenden Quelle in das aktuelle Verzeichnis. Dies umfasst alle verfügbaren Patches, die automatisch auf den heruntergeladenen Quelltext angewendet werden.
check
Prüft die lokalen Paketlisten auf Konsistenz und sucht nach nicht erfüllten Abhängigkeiten zwischen installierten Paketen.
clean
Entfernt heruntergeladene Paketdateien.
autoclean
Entfernt heruntergeladene Paketdateien von Paketen, die nicht mehr verfügbar sind.
autoremove
Entfernt automatisch installierte Pakete, die nicht mehr benötigt werden, da sie keine Abhängigkeit mehr erfüllen müssen.
Tabelle 2.3 Wichtige Parameter von apt-get
Um die Verfügbarkeit aktueller Patches und Updates zu prüfen und diese anschließend zu installieren, müssen nacheinander die folgenden Befehle ausgeführt werden: apt-get update apt-get upgrade
54
Feintuning
Es ist wichtig, das Update vor dem Upgrade durchzuführen, da APT ansonsten gar keine Kenntnis über verfügbare Updates hat. Wie und warum der Update-Prozess und das Einspielen von Patches automatisiert werden sollte, ist Gegenstand von Kapitel 7, »Serverwartung«. APT kennt Abhängigkeiten zwischen Paketen, was eine Grundvoraussetzung für einen modernen Paketmanager ist. Wird ein Paket installiert, das ein anderes Paket für sein Funktionieren benötigt, macht apt-get darauf aufmerksam und installiert bei Bedarf dieses Paket automatisch. Metapakete Neben normalen Paketen, die jeweils einzelne Programme enthalten, gibt es so genannte Metapakete. Diese enthalten selbst keine Programme, sondern fassen zusammenhängende Pakete zu einem Paket zusammen. Beispiele dafür sind das Metapaket build-essential, das die wichtigsten Pakete, die für ein Entwicklungssystem benötigt werden, zusammenfasst. Anstatt alle Pakete einzeln installieren zu müssen (Compiler, Bibliotheken etc.) wird lediglich das Metapaket installiert, das die benötigten Pakete definiert und APT anweist, diese zu installieren. Weitere Beispiele sind die Desktopumgebungen der offiziellen Ubuntu-Versionen: ubuntu-desktop, kubuntu-desktop, xubuntu-desktop und edubuntu-desktop.
dpkg apt-get und apt-cache sind für Update und Pflege des Systems zuständig. Um sich einen Überblick über die bereits installierten Pakete zu verschaffen, muss allerdings ein weiteres Programm bemüht werden, dpkg. In Teilen überschneidet sich die Funktionalität von apt-get, apt-cache und dpkg. Die Funktionalität aller Programme zusammen wird in Metaprogrammen wie aptitude zusammengefasst. Da diese Metaprogramme aber nur Frontends für die entsprechenden Programme darstellen – in der Programmierung würde man von syntaktischem Zucker sprechen –, wird an dieser Stelle auf eine Beschreibung derselben verzichtet. Die Funktionalität ergibt sich aus der Summe der jeweiligen Einzelfunktionalität der hier vorgestellten Programme.
Mit dpkg können bereits installierte Pakete verwaltet oder einzelne Pakete installiert werden. Im Zusammenspiel mit apt-get und apt-cache stehen mit dpkg alle Möglichkeiten zur Verfügung, die ein modernes Paketmanagement bieten sollte. Die folgenden Beispiele zeigen die wichtigsten mit dpkg ausführbaren Operationen. Der Befehl dpkg -l gibt eine Liste der installierten Pakete aus: Desired=Unknown/Install/Remove/Purge/Hold | Status=Not/Installed/Config-f /Unpacked/Failed-cfg/Half-inst/t-aWait/T-pend
55
2.3
2
Installation und Konfiguration
|/ Err?=(none)/Hold/Reinst-required/X=bothproblems (Status,Err: uppercase=bad) ||/ Name Version Beschreibung +++================================================================= ii adduser 3.105ubuntu1 add and remove users and groups ii apache2 2.2.8-1 Next generation, scalable, extendable web se ii apache2-mpm-prefork 2.2.8-1 Traditional model for Apache HTTPD ii apache2-utils 2.2.8-1 utility programs for webservers ii apache2.2-common 2.2.8-1 Next generation, scalable, extendable web se ii apparmor 2.1+1075-0ubuntu9 User-space parser utility for AppArmor ii apparmor-utils 2.1+1075-0ubuntu9 Utilities for controlling AppArmor ii apt 0.7.9ubuntu16 Advanced front-end for dpkg ii apt-utils 0.7.9ubuntu16 APT utility programs ...
In der ersten Spalte ist der Status des jeweiligen Paketes angegeben. Dieser setzt sich aus zwei Werten zusammen. Der erste Wert gibt den für das Paket vorgemerkten Status an, der zweite Wert den aktuellen Status. Der vorgemerkte Status kann durch apt-get oder Metasoftware gesetzt werden, um die entsprechende Aktion beim nächsten Durchlauf auszuführen. Folgende vorgemerkte Status sind möglich: Status
Bedeutung
i
install (Paket wird installiert)
u
unknown (Status unbekannt)
r
remove (Paket wird gelöscht)
p
purge (Paket wird gepurged)
Tabelle 2.4 Status verfügbarer Ubuntu-Pakete
56
Feintuning
Aktuelle Status sind folgende möglich: Status
Bedeutung
i
installed (Paket ist installiert)
c
unknown (Status unbekannt)
n
not installed (Paket ist nicht installiert)
u
unpacked (Paket ist heruntergeladen und entpackt, aber nicht konfiguriert)
f
failed config (Konfiguration des Paketes fehlgeschlagen)
h
half installed (Installation des Paketes unvollständig)
Tabelle 2.5 Status installierter Ubuntu-Pakete
Der Befehl dpkg -s < paketname> gibt nähere Informationen zu einem installierten Paket aus: # dpkg -s ufw Package: ufw Status: install ok installed Priority: optional Section: admin Installed-Size: 204 Maintainer: Jamie Strandboge <[email protected]> Architecture: all Version: 0.16.2 Depends: debconf, iptables (>= 1.3.3), python (>= 2.5), ucf Conffiles: /etc/ufw/sysctl.conf 5dccb53706555991e5950ccfbe5c9283 /etc/default/ufw 2516dfe8eac8b23bd36011f23b41ef37 /etc/init.d/ufw 1ee79abb604e4b485c83fde7e774dadd Description: program for managing a netfilter firewall Ufw is a tool to manage a local host-based firewall. It provides a command line interface and aims to be uncomplicated and easy to use. Homepage: https://launchpad.net/ufw Python-Version: >= 2.5
Ein einzeln aus dem Internet geladenes Paket kann über den Schalter -i installiert werden: dpkg -i <paketname> Gentoo: Portage Der Paketmanager von Gentoo ist Portage, der die Arbeit erledigt, alle Pakete aus dem Quelltext zu übersetzen. Die Softwarepakete werden in so genannten ebuilds beschrieben. Ein ebuild enthält Informationen darüber, wo Portage den Quelltext des Paketes finden kann, welche Abhängigkeiten erfüllt sein müssen und wie der
57
2.3
2
Installation und Konfiguration
Quelltext übersetzt wird. ebuilds sind auf einem Gentoo-System im Verzeichnis /usr/portage abgelegt, dem so genannten Portage-Tree. Der Header eines beliebigen ebuilds (in diesem Beispiel der des Programms sed) zeigt, welche Informationen im ebuild stecken: # Copyright 1999-2007 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 # $Header: /var/cvsroot/gentoo-x86/sys-apps/sed/ sed-4.1.5.ebuild,v 1.20 2007/11/04 03:34:44 vapier Exp $ inherit flag-o-matic DESCRIPTION="Super-useful stream editor" HOMEPAGE="http://sed.sourceforge.net/" SRC_URI="mirror://gnu/sed/${P}.tar.gz" LICENSE="GPL-2" SLOT="0" KEYWORDS="alpha amd64 arm hppa ia64 m68k mips ppc ppc64 s390 sh sparc ~sparc-fbsd x86 ~x86-fbsd" IUSE="nls static" RDEPEND="nls? ( virtual/libintl )" DEPEND="${RDEPEND} nls? ( sys-devel/gettext )"
Portage lädt den Quelltext des Programms nicht von einem Gentoo-Server, sondern von einem Server, der zu dem jeweiligen Programm gehört. Genau wie bei Ubuntu muss die Liste der verfügbaren Pakete (ebuilds) aktuell gehalten werden. Die Schnittstelle zum Portage-System ist das Programm emerge, mit dem auch der Portage-Tree aktualisiert wird. Dies kann mit rsync oder webrsync durchgeführt werden, Letzteres arbeitet über HTTP und ist damit auch über Proxyserver möglich: # emerge-webrsync Fetching most recent snapshot Attempting to fetch file dated: 20080419 portage-20080419.tar.bz2: OK Syncing local tree... [...]
Suche und Installation von Paketen geschieht ebenfalls mit emerge. Der Parameter --search sucht nach einem Paketnamen, dem der übergebene Ausdruck entspricht. Der Parameter --searchdesc durchsucht auch die Paketbeschreibungen nach dem übergebenen Ausdruck.
58
Feintuning
# emerge --search curl Searching... [ Results for search key : curl ] [ Applications found : 5 ] *
dev-lisp/cl-curl [ Masked ] Latest version available: 20050609 Latest version installed: [ Not Installed ] Size of files: 9 kB Homepage: http://sourceforge.net/projects/cl-curl/ Description: Common Lisp interface to libcurl, a multiprotocol file transfer library License: LLGPL-2.1
*
dev-ml/ocurl Latest version Latest version Size of files: Homepage: Description: License: [...]
available: 0.2.1 installed: [ Not Installed ] 73 kB http://sourceforge.net/projects/ocurl OCaml interface to the libcurl library MIT
Wenn im Anschluss an die Installation CFLAGS und USE-Flags korrekt gesetzt worden sind (siehe Abschnitt 2.2.1), kann durch Aufruf von emerge <paketname> das betreffende Paket installiert werden. Die CFLAGS können nachträglich in der Datei /etc/make.conf editiert werden. Globale USE-Flags werden ebenfalls in dieser Datei konfiguriert – für den Einstieg ist die Beispieldatei /etc/make.conf.example ein guter Ausgangspunkt. Lokale USE-Flags werden in der Datei /etc/portage/portage.use festgelegt. Um beispielsweise das Paket sipcalc ohne GnomeUnterstützung zu kompilieren (was überdies wenig Sinn ergäbe), wäre der entsprechende Eintrag in der Datei portage.use: net-misc/sipcalc -gnome
Beachten Sie, dass bei Gentoo jedes Paket aus dem Quelltext übersetzt wird und der Installationsvorgang je nach Prozessorleistung, verfügbarem Speicher und Umfang des Quelltextes entsprechend lange dauern kann. Die Installation des Programms sipcalc, die unter Ubuntu wenige Sekunden dauert, nimmt auf einem Pentium M mit 1,8 GHz immerhin schon 30 Sekunden in Anspruch: # time emerge sipcalc Calculating dependencies... done! >>> Verifying ebuild Manifests... >>> Emerging (1 of 1) net-misc/sipcalc-1.1.4 to /
59
2.3
2
Installation und Konfiguration
* sipcalc-1.1.4.tar.gz RMD160 SHA1 SHA256 size ;-) ... [...] real 0m30.168s user 0m3.120s sys 0m21.110s
Bei umfangreichen Paketen wie Emacs, OpenOffice oder Gnome kann die Installation mitunter mehrere Stunden dauern – in der Regel werden diese Programmpakete auf einem Server aber ohnehin nicht benötigt.
2.3.2
Konfiguration von OpenSSH
Der erste Schritt bei der Konfiguration eines Systems ist das Einrichten eines Administrationszugangs. Das Mittel der Wahl dabei ist SSH. SSH ist ein verschlüsseltes Netzwerkprotokoll, mit dem ein Benutzer eine Shell auf einem entfernten System öffnen und Daten übertragen kann. Darüber hinaus können über eine SSHVerbindung weitere Verbindungen getunnelt werden. Die bekannteste OpenSource-Software für SSH ist OpenSSH und stellt einen SSH-Server sowie einen SSH-Client zur Verfügung. OpenSSH ist für Gentoo und Ubuntu erhältlich und kann über die distributionseigenen Paketmanager installiert werden. Die Website von OpenSSH2 enthält umfangreiche Dokumentationen zu OpenSSH und der Verwendung von SSH. Installation von OpenSSH Unter Ubuntu befindet sich der OpenSSH-Server im Paket openssh-server, der Client in openssh-client. Die Installation erfolgt mit apt-get: apt-get install openssh-server openssh-client
Unter Gentoo kommt für die Installation emerge zum Einsatz: emerge openssh
Um einen sicheren Zugang zum Server zu erhalten, sind ein paar Feinheiten in der Konfiguration des SSH-Dienstes zu beachten. SSH bietet verschiedene Möglichkeiten der Authentifizierung. Die unsicherste ist die über Benutzername und Passwort, da ein Angreifer mit Hilfe eines Brute-Force-Angriffes versuchen kann, das Passwort zu erraten. Entsprechende Angriffe laufen ständig und automatisiert auf Hosts im Internet. Wenn das verwendete Passwort obendrein ein schwaches Passwort ist, ist die Kompromittierung des Servers nur eine Frage der Zeit. Aus diesem Grund sollte grundsätzlich nur die sicherste Authentifizierungsmethode von SSH verwendet werden, die Authentifizierung über ein Public-KeyVerfahren. Dazu wird auf einem Client-Rechner ein SSH-Schlüsselpaar erzeugt. 2 http://www.openssh.org/
60
Feintuning
Der öffentliche Schlüssel wird auf dem Server hinterlegt, und der Benutzer authentifiziert sich gegenüber dem Server durch seinen privaten Schlüssel, der vom Server anhand des öffentlichen Schlüssels überprüft wird. Da es sich bei dem Schlüsselpaar um RSA-Schlüssel handelt, d. h. um einen als sicher angesehenen Algorithmus, kann die Authentifizierung über das Public-Key-Verfahren als sicher betrachtet werden. Für die Sicherheit von Public-Key-Verfahren sei an dieser Stelle auf die einschlägige Fachliteratur verwiesen (z. B. auf »Applied Cryptography« von Bruce Schneier). Ein Angreifer hat keine Möglichkeit, den privaten Schlüssel eines Benutzers durch einen Brute-Force-Angriff zu ermitteln. Wichtig ist aber, dass der SSH-Server so konfiguriert wird, dass er nur Public-Key-Authentifizierung akzeptiert. Leider ist dies bei den gängigen Distributionen nicht der Fall, die SSH-Server akzeptieren die Authentifizierung über Benutzername/Passwort und Public Key. Der erste Schritt zur Absicherung des SSH-Dienstes ist das Erzeugen eines eigenen Schlüsselpaares. Dies wird auf dem zur Administration verwendeten System mit dem Befehl ssh-keygen durchgeführt: # ssh-keygen Generating public/private rsa key pair. Enter file in which to save the key (/home/kr/.ssh/id_rsa): Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/kr/.ssh/id_rsa. Your public key has been saved in /home/kr/.ssh/id_rsa.pub. The key fingerprint is: f4:36:a0:92:3a:37:86:69:61:28:51:31:f5:aa:6f:f4 kr@hardy
Das Passwort dient der Sicherheit des privaten Schlüssels. Damit wird verhindert, dass jemand, der den privaten Schlüssel in seinen Besitz bringt, diesen verwenden kann. Aus diesem Grund sollte bei der Erstellung des Schlüsselpaares grundsätzlich ein starkes Passwort vergeben werden. Im Anschluss an die Erstellung des Schlüsselpaares befinden sich im Verzeichnis ~/.ssh/ zwei Dateien: id_rsa und id_rsa.pub. Die erste Datei enthält den privaten Schlüssel und darf nie in fremde Hände gelangen. Die zweite Datei ist der zum privaten Schlüssel gehörende öffentliche Schlüssel. Dieser Schlüssel kann ohne Gefahr verteilt werden und muss auf jedem System vorhanden sein, an dem man sich über dieses Schlüsselpaar anmelden möchte. Der SSH-Server erwartet den öffentlichen Schlüssel eines Benutzers in der Datei ~/.ssh/authorized_keys – sofern in der Konfiguration des Servers nichts anderes festgelegt worden ist. Der öffentliche Schlüssel muss daher nur auf den Server an die besagte Stelle kopiert werden.
61
2.3
2
Installation und Konfiguration
Solange die Authentifizierung über Benutzername und Passwort nicht deaktiviert ist, kann das Übertragen des öffentlichen Schlüssels über SSH realisiert werden: scp id_rsa.pub server:.ssh/authorized_keys
SCP ist ein Programm zum Übertragen von Dateien über SSH und wird in Kapitel 4, »Serverdienste«, näher erläutert. Wichtig: Standardmäßig gibt es auf einem neu installierten System kein ssh-Verzeichnis für einen Benutzer. Es muss daher vor dem Kopieren des Schlüssels noch angelegt werden. Wichtig ist ebenfalls, dass die Zugriffsrechte dieses Verzeichnisses und der darin enthaltenen Dateien stimmen, da der SSH-Server – je nach Konfiguration – den öffentlichen Schlüssel sonst nicht akzeptiert: # ls -la .ssh/ total 20 drwx------ 2 kr drwxr-xr-x 3 kr -rw-r--r-- 1 kr -rw------- 1 kr -rw-r--r-- 1 kr
Ist der öffentliche Schlüssel übertragen und befindet sich in der Datei authorized_ keys, kann die Public-Key-Authentifizierung verwendet werden. Bei der Anmeldung per SSH am Server fragt dieser nun nach der Passphrase des SSH-Schlüssels. Der nächste Schritt besteht darin, den SSH-Server zu härten, d. h. unsichere Einstellungen zu deaktivieren. Im Folgenden werden die dafür relevanten Direktiven der Konfiguration aufgeführt. Eine vollständige Übersicht über alle Konfigurationsmöglichkeiten enthält die passende Manpage (man sshd_config). Mit der Direktive Port 22 wird der TCP-Port festgelegt, auf dem der SSH-Server auf eingehende Verbindungen wartet. Das Ändern des Ports auf einen anderen Wert stellt in sich noch keinen nennenswerten Sicherheitsgewinn dar – Security through Obscurity ist nur ein schwacher Schutz –, hilft aber zumindest gegen die automatisierten SSH-Scanner, mit denen Angreifer Brute-Force-Angriffe auf beliebige Systeme im Internet ausführen. Die Verwendung eines hohen Ports, der nicht zu den Triggerports gängiger Portscanner gehört, ist empfehlenswert, da dies die Wahrscheinlichkeit der Entdeckung des Servers durch einen Portscanner verringert. Die SSH-Protokollversion 1 ist unsicher, weswegen die vom Server verwendete Protokollversion mit der Direktive Protocol 2 auf die Protokollversion 2 festgelegt werden muss.
62
Feintuning
Durch die Direktive UsePrivilegeSeparation yes wird der SSH-Server angewiesen, für das Empfangen eingehender Netzwerkverbindungen einen unprivilegierten Prozess zu verwenden. Erst nach erfolgreicher Authentifizierung wird ein neuer Prozess mit den Rechten des jeweiligen Benutzers erstellt. Dies verhindert Angriffe durch so genannte Privilege Escalation, Sicherheitslücken, durch die sich ein Angreifer erweiterte Rechte verschaffen kann. Eine verbreitete Unsitte ist es, mit Root-Rechten zu arbeiten. Um zu verhindern, dass sich ein Benutzer direkt als root per SSH anmelden kann, wird dies mit der Direktive PermitRootLogin no verboten. Die Direktive StrictModes yes veranlasst den SSH-Server, die Dateisystem-Berechtigungen des jeweiligen Benutzerverzeichnisses und insbesondere des darin enthaltenen Verzeichnisses .ssh/ samt der darin enthaltenen Dateien zu prüfen. Damit wird verhindert, dass ein Angreifer falsch gesetzte Rechte eines Benutzerverzeichnisses ausnutzen kann, um beispielsweise einen eigenen Public Key in das ssh-Verzeichnis eines anderen Benutzers zu legen oder um die dort liegenden SSH-Schlüssel auszulesen. Die Verwendung der Public-Key-Authentifizierung wird mit der Direktive PubkeyAuthentication yes erlaubt. Genau genommen ist die Public-Key-Authentifizierung standardmäßig erlaubt, auch wenn diese Direktive nicht gesetzt ist. Im Sinne der Übersichtlichkeit der Konfigurationsdatei ist es aber dennoch ratsam, diese Direktive explizit zu setzen. Die Anmeldung mit Benutzername/Passwort und anderen Identifizierungsmechanismen, die alle als unsicher betrachtet werden müssen, werden mit den folgenden Direktiven deaktiviert: IgnoreRhosts yes RhostsRSAAuthentication no HostbasedAuthentication no PermitEmptyPasswords no ChallengeResponseAuthentication no PasswordAuthentication no
Zum Schluss sollte mit der Direktive X11Forwarding no das Weiterleiten von X11-Verbindungen verboten werden. Standardmäßig gesetzt ist die Direktive Subsystem sftp /usr/lib/openssh/ sftp-server. Dies ermöglicht das Übertragen von Dateien über SSH mit SCP oder
SFTP. Diese Direktive sollte unbedingt gesetzt bleiben, damit Dateien sicher vom und zum Server übertragen werden können.
63
2.3
2
Installation und Konfiguration
2.3.3
Benutzer anlegen
Bei der Installation von Gentoo werden ein Benutzer- und ein Root-Konto angelegt. Das Root-Konto ist für Arbeiten am System benutzbar, nichtsdestotrotz sollte sudo vorgezogen werden. sudo erlaubt das selektive Ausführen von Befehlen mit Root-Rechten und verhindert damit, dass dauerhaft mit Root-Rechten gearbeitet wird. Letzteres birgt zwei große Gefahren: Zum einen kann ein Benutzer mit Root-Rechten absichtlich oder aus Versehen großen bis irreparablen Schaden am System anrichten. Ein gedankenlos mit Root-Rechten abgeschicktes rm -rf / löst zunächst sehr viel Festplattenaktivität aus und verursacht im Nachgang eine Menge Arbeit. Ubuntu legt zwar ein Root-Konto an, dieses ist aber nicht benutzbar, da dafür bei der Installation kein Passwort vergeben wird. Stattdessen setzt Ubuntu komplett auf sudo. Frühere Versionen von Ubuntu haben gar kein Root-Konto verwendet, erst im Lauf der Zeit hat sich dieses Paradigma geändert. Da sudo integraler Bestandteil der Ubuntu-Philosophie ist, muss es nach der Installation nicht zusätzlich installiert und konfiguriert werden. Das Programm ist so konfiguriert, dass jedes Mitglied der Gruppe admin Programme mit Root-Rechten ausführen darf. Unter Gentoo muss sudo zunächst mit dem Befehl emerge sudo installiert und anschließend konfiguriert werden. sudo wird über die Datei /etc/sudoers konfiguriert. Um die parallele Bearbeitung der Datei zu verhindern und um dafür zu sorgen, dass die Rechte der Datei korrekt gesetzt sind, sollte die Datei ausschließlich über den Befehl visudo bearbeitet werden, der genau diese Punkte sicherstellt. Da falsche Einträge in der Konfigurationsdatei fatale Folgen haben können – bis hin zu Root-Rechten für Benutzer, die gar keine Root-Rechte haben dürfen –, ist besondere Sorgfalt bei der Konfiguration von sudo angezeigt. Bei Ubuntu besteht die Konfiguration von sudo darin, dass jeder Benutzer der Gruppe admin Befehle mit Root-Rechten ausführen darf. Dies wird durch den folgenden Eintrag in der Datei /etc/sudo festgelegt: %admin ALL=(ALL) ALL
Um diese Funktionalität unter Gentoo zu erreichen, muss der mit diesen Rechten auszustattende Benutzer zunächst einer entsprechenden Gruppe hinzugefügt werden. Diese Gruppe wird mit dem Befehl groupadd erzeugt: groupadd admin
Standardmäßig sind Benutzer unter Gentoo Mitglied der Gruppe users. Um einen Benutzer einer zweiten Gruppe hinzuzufügen, wird die Gruppe mit dem Befehl usermod als sekundäre Gruppe des Benutzers definiert:
64
Feintuning
usermod -G users,admin kr
Anschließend wird der oben gezeigte Auszug aus der Datei /etc/sudo von Ubuntu mit visudo der sudo-Konfiguration hinzugefügt. Um einen Befehl mit Root-Rechten auszuführen, wird diesem einfach der Befehl sudo vorangestellt, z. B.: sudo vi /etc/ssh/sshd_config
Der Benutzer wird dann aufgefordert, sein Passwort einzugeben, und kann dann die Datei /etc/ssh/sshd_config bearbeiten. Dass der Befehl sudo Root-Rechte verleiht, zeigt der Aufruf von id einmal ohne und einmal mit sudo: # id uid=1000(kr) gid=1000(kr) groups=100(users),1000(kr),1001(admin) # sudo id uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),1 1(floppy),20(dialout),26(tape),27(video)
Das Minimal-Prinzip Die Philosophie hinter sudo ist das selektive Verwenden von Root-Rechten, um Sicherheitslücken oder Gefahren durch unbedachte Arbeiten zu vermeiden. Der Befehl sudo bash startet für einen Benutzer eine Bash mit Root-Rechten, hebelt allerdings das Prinzip von sudo komplett aus. Setzen Sie Root-Rechte nur dann ein, wenn sie wirklich benötigt werden.
2.3.4
Konfiguration der Bash
Die Standard-Shell, die ein Benutzer verwendet, ist unter Gentoo und Ubuntu die Bash. Festgelegt wird dies durch einen entsprechenden Eintrag in der Datei /etc/ passwd: kr:x:1000:1000:kr,,,:/home/kr:/bin/bash
Das Verhalten der Bash kann durch Setzen verschiedenster Variablen konfiguriert werden. Da niemand diese Variablen bei jedem neuen Aufruf der Bash händisch setzen möchte, gibt es verschiedene Dateien, mit denen die Bash konfiguriert werden kann. Die Bash führt die darin enthaltenen Befehle beim Einlesen der jeweiligen Datei aus: /etc/profile /etc/bash.bashrc ~/.bash_profile
65
2.3
2
Installation und Konfiguration
~/.profile ~/.bash_login ~/.bash_logout ~/.bashrc Die ersten sechs Dateien werden von der Bash bei ihrem Start eingelesen, wenn sie als Login-Shell gestartet wird. Dies ist dann der Fall, wenn die Bash mit dem Parameter --login aufgerufen wird oder wenn sich ein Benutzer am System anmeldet, beispielsweise per SSH. Die Dateien /etc/profile und /etc/bash.bashrc dienen der systemweiten Einstellung von Bash-Parametern, d. h. von Einstellungen, die für alle Benutzer gelten. Die Dateien ~/.bash_login, ~/.bash_profile und ~/.profile sind – wie die Tilde vor dem Dateinamen zeigt – benutzerspezifische Dateien, über die jeder Benutzer eigene Einstellungen für die Bash vornehmen kann. Beim Verlassen einer interaktiven Shell liest die Bash noch die Datei ~/.bash_logout und führt die darin enthaltenen Befehle aus. Beim Start einer interaktiven Shell, die keine Login-Shell ist, also beispielsweise beim Öffnen einer Shell durch einen bereits angemeldeten Benutzer, werden die Dateien /etc/bash.bashrc und ~/.bashrc von der Bash gelesen. Überprüfen lassen sich diese Dateizugriffe mit dem Tool strace, mit dem Systemund Bibliotheksaufrufe von Programmen protokolliert werden können. Der Befehl … strace -e trace=file /bin/bash
… protokolliert alle Dateizugriffe, die durch die Bash erfolgen. Die Ausgabe bestätigt die oben getroffene Aussage. Im Folgenden sind nur die relevanten Ausgaben des Befehls aufgeführt: open("/etc/bash.bashrc", O_RDONLY|O_LARGEFILE) = 3 open("/home/kr/.bashrc", O_RDONLY|O_LARGEFILE) = 3 open("/home/kr/.bash_history", O_RDONLY|O_LARGEFILE) = 3 [22:29:07] --- kr@hardy:~ # exit exit open("/home/kr/.bash_history", O_WRONLY|O_APPEND|O_LARGEFILE) = 3 Process 11369 detached
Beim Aufruf wird zunächst die Datei /etc/bash.bashrc eingelesen, anschließend die Dateien ~/.bashrc und ~/.bash_history. Letztere enthält keine Konfigurations-
66
Feintuning
anweisungen für die Bash, sondern speichert alle in der Bash abgesetzten Befehle, um dem Benutzer Zugriff auf (s)eine Befehlshistorie zu ermöglichen. Nach dem Beenden der Bash schreibt diese die letzten abgesetzten Befehle in die History und beendet sich dann. Der Aufruf der Bash als Login-Shell bringt erwartungsgemäß die entsprechenden Resultate: strace -e trace=file /bin/bash --login open("/etc/profile", O_RDONLY|O_LARGEFILE) = 3 open("/etc/bash.bashrc", O_RDONLY|O_LARGEFILE) = 3 open("/home/kr/.bash_profile", O_RDONLY|O_ LARGEFILE) = -1 ENOENT (No such file or directory) open("/home/kr/.bash_login", O_RDONLY|O_ LARGEFILE) = -1 ENOENT (No such file or directory) open("/home/kr/.profile", O_RDONLY|O_LARGEFILE) = 3 open("/home/kr/.bashrc", O_RDONLY|O_LARGEFILE) = 3 open("/home/kr/.bash_history", O_RDONLY|O_LARGEFILE) = 3 [22:37:40] --- kr@hardy:~ # exit logout open("/home/kr/.bash_logout", O_RDONLY|O_LARGEFILE) = 3 open("/home/kr/.bash_history", O_WRONLY|O_APPEND|O_LARGEFILE) = 3 Process 11513 detached
Hier wird neben dem Einlesen der entsprechenden Dateien beim Beenden der Bash auch noch die Datei ~/.bash_logout eingelesen. Interessant an dieser Ausgabe ist, dass die Bash das Fehlen einer Konfigurationsdatei nicht persönlich nimmt, sondern lediglich feststellt, dass diese Datei fehlt. Wenn keine der möglichen Konfigurationsdateien existiert, startet die Bash mit ihren Standardeinstellungen. Neben dem Ausführen von Befehlen durch die beschriebenen Dateien können in diesen Dateien beliebige Umgebungsvariablen gesetzt werden, mit denen die Bash oder andere Programme konfiguriert werden können. Ein buntes Prompt, das den aktuellen Pfad anzeigt, kann über die Variable PS1 in einer der obenstehenden Dateien gesetzt werden: export PS1="\[\033[0;36m\]\u\[\033[32m\]@\[\033[35m\]\h\[\033[33m\]:\w #\[\033[0;39m\] "
Das Schlüsselwort export vor dem Variablennamen gibt an, dass die Änderung auch für weitere, von dieser Shell erzeugte Shells gilt. Denken Sie bei der Verwendung der Konfigurationsdateien immer daran, welche Datei wann aufgeru-
67
2.3
2
Installation und Konfiguration
fen wird. Der Einfachheit halber kann in vielen Fällen ein symbolischer Link von ~/.profile auf ~/.bashrc Arbeit verhindern – egal ob Login-Shell oder nicht: In beiden Fällen werden dieselben Einstellungen geladen. Ob dies im Einzelfall wünschenswert ist, hängt natürlich vom jeweiligen Benutzer ab. Weitere wichtige Umgebungsvariablen, mit denen die Bash oder andere Programme flexibel an die eigenen Bedürfnisse angepasst werden können, enthält die folgende Tabelle. Eine vollständige Aufstellung der Bash-Variablen enthält die Manpage der Bash. Variable
Bedeutung
HISTSIZE
Maximale Anzahl von Kommandos, die in der Bash-History gespeichert wird.
PATH
Suchpfad, in dem die Bash nach ausführbaren Programmen sucht.
EDITOR
Gibt den Editor an, der von Programmen wie visudo oder crontab abgerufen wird.
HTTP_PROXY
Definiert einen Proxy-Server, der von Programmen für HTTP-Verbindungen verwendet werden soll.
SUDO_PROMPT
Definiert das Aussehen des Prompts, das von sudo angezeigt wird. Standardmäßig ist das Prompt von sudo leer, ein selbstdefiniertes Prompt erhöht die Übersichtlichkeit.
Tabelle 2.6
Wichtige Umgebungsvariablen der Bash
Neben Variablen können über die Konfigurationsdateien der Bash auch Aliase erzeugt werden. Ein Alias ist ein neuer Name für einen beliebigen Befehl (mit beliebigen Parametern). Mit dem Alias … alias dir=’ls -la’
… wird der Alias dir festgelegt, der beim Aufruf den Befehl ls -la ausführt. Ist man von anderen Betriebssystemen bestimmte Kommandos gewöhnt, kann man sich diese über Aliase in der Bash selbst zusammenstellen. Darüber hinaus können über Aliase häufig wiederkehrende Arbeitsschritte zusammengefasst und vereinfacht werden. Umgebungsvariablen bei einer nicht-interaktiven Shell Ein häufig gemachter Fehler besteht darin, für eine Bash, die nicht interaktiv aufgerufen wird – also z. B. im Rahmen eines Cron-Jobs –, die in den Konfigurationsdateien vorgenommenen Einstellungen vorauszusetzen. Dies funktioniert nicht, da eine nicht-interaktive Shell diese Dateien nicht einliest. Stattdessen verwendet eine solche Shell die in der Datei BASH_ENV festgelegte Konfigurationsdatei.
68
Feintuning
2.3.5
Umask
Im Hinblick auf die im nächsten Kapitel behandelte Systemhärtung ist an dieser Stelle noch der Hinweis auf einen wichtigen Eintrag in der Datei /etc/profile angebracht. Unter Linux besitzen Dateien und Verzeichnisse Zugriffsrechte. Diese gliedern sich in Rechte für den Besitzer einer Datei oder eines Verzeichnisses, in Rechte für die Gruppe, der die Datei oder das Verzeichnis gehört, und in Rechte für alle anderen, die weder der Besitzer sind noch zur Besitzergruppe gehören. Die Zugriffsrechte werden über eine Oktalzahl bzw. Buchstaben dargestellt. Die Berechtigungen einer Datei oder eines Verzeichnisses zeigt der Befehl ls -la an: # ls -la insgesamt 484 drwxr-xr-x 63 drwxr-xr-x 3 drwx------ 5 -rw------- 1 -rw-r--r-- 1
Die Buchstaben auf der linken Seite geben die Berechtigungen der jeweiligen Datei oder des Verzeichnisses an. Der erste Buchstabe zeigt an, ob es sich um ein Verzeichnis handelt (d) oder um eine Datei (-). Dann folgen in Dreiergruppen die Berechtigungen für den Eigentümer, für die Gruppe und für den Rest der Welt. Dabei steht ein r für Leseberechtigung, w für Schreibberechtigung und x für die Berechtigung, die Datei auszuführen. Bei Verzeichnissen ist die Berechtigung zum Ausführen notwendig, um in das jeweilige Verzeichnis wechseln zu können. Im vorstehenden Beispiel kann der Benutzer kr lesend und schreibend auf die Datei .bash_logout zugreifen. Benutzer aus der Gruppe kr dürfen lesend auf diese Datei zugreifen – ebenso wie alle anderen Benutzer. Auf die Datei .bash_history hingegen darf lediglich der Benutzer kr lesend und schreibend zugreifen, alle anderen Benutzer haben keinen Zugriff. Neben der Darstellung der Zugriffsrechte durch Buchstaben kann auch eine Oktalzahl verwendet werden. Jeder der drei Zugriffsmöglichkeiten »lesen«, »schreiben«, »ausführen« ist eine Zahl zugeordnet. Durch die Kombination dieser Zahlen ergibt sich pro Datei oder Verzeichnis eine eindeutige Oktalzahl.
69
2.3
2
Installation und Konfiguration
d
r
w
x
r
w
x
r
w
x
4
2
1
4
2
1
4
2
1
u
g
w
a
Abbildung 2.3 Zugriffsrechte im Überblick
Für die Datei .bash_logout aus dem vorstehenden Beispiel ergibt sich damit der Wert 644. Die beiden Werte für Lese- und Schreibzugriff (4+2) des Eigentümers werden addiert, die Werte für den Lesezugriff der Gruppe (4) und aller anderen (4) separat notiert. Das Programm chmod, mit dem Zugriffsrechte gesetzt werden, kennt beide Arten der Notation. Der Befehl … chmod u+w
… fügt Schreibrechte für den Benutzer hinzu. Der Befehl … chmod 660
… setzt die Rechte der Datei so, dass Benutzer und Gruppe lesend und schreiben darauf zugreifen dürfen, der Zugriff für alle anderen hingegen verboten ist. Standardmäßig werden neue Dateien und Verzeichnisse so angelegt, dass Vollzugriff für alle besteht: [20:36:08] --- kr@hardy:/tmp/test # dir insgesamt 4 drwxrwxrwx 2 kr kr 4096 2008-05-03 20:35 one -rw-rw-rw- 1 kr kr 0 2008-05-03 20:35 two
Das Verzeichnis one hat die Rechte 777, die Datei two die Rechte 666. Dies stellt ein grundsätzliches Sicherheitsrisiko dar, denn auch Dateien und Verzeichnisse mit sensiblen Inhalten sind so für jedermann lesbar. Im Rahmen des BestPractice-Ansatzes Secure by Default sollte der Zustand umgekehrt sein. Die Rechte für neue Dateien und Verzeichnisse sollten automatisch so restriktiv wie möglich vergeben werden. Möchte ein Benutzer oder der Systemverwalter bestimmte Da-
70
Feintuning
teien und Verzeichnisse dennoch für alle Benutzer und Gruppen freigeben, muss dies explizit durchgeführt werden. Festgelegt werden die Zugriffsrechte für neue Dateien und Verzeichnisse über die so genannte Umask. Die Umask ist eine Bitmaske in Form einer Oktalzahl, analog zur Oktaldarstellung der Zugriffsberechtigung. Ausgehend von den größtmöglichen Zugriffsrechten – 777 für Verzeichnisse und 666 für Dateien – wird die Umask vom jeweiligen Wert subtrahiert, um die Zugriffsberechtigungen für neue Dateien und Verzeichnisse zu erhalten. Eine Umask von 022, die bei vielen Linux-Distributionen als Standard definiert wird, bedeutet, dass von einem Vollzugriff auf ein Verzeichnis (777) der Wert 022 abgezogen wird. Das Ergebnis ist die Berechtigung 755 für Verzeichnisse. Vollzugriff auf Verzeichnis: 777 Umask (wird subtrahiert): 022 Tatsächliche Berechtigung: 755
Bei Dateien besteht der Vollzugriff aus der Oktalzahl 666, davon 022 subtrahiert führt zu der Berechtigung 644. Vollzugriff auf Verzeichnis: 666 Umask (wird subtrahiert): 022 Tatsächliche Berechtigung: 644
Der Standardwert der Umask von 022 ist für einen Server nicht angemessen. Standard sollte sein, dass eine Datei oder ein Verzeichnis nur vom eigenen Benutzer geöffnet werden darf. Daher sollte die Umask auf 077 gesetzt werden, was zur Folge hat, dass die Berechtigungen für neue Verzeichnisse auf 700 gesetzt werden und die für neue Dateien auf 600. Das Paradigma Secure by Default wäre damit erfüllt. Eine Umask von 077 ist kein Muss. Es kann gute Gründe für andere Werte geben, dies hängt von den individuellen Anforderungen an ein System ab. Festgelegt wird die Umask in der Datei /etc/profile: umask 022
71
2.3
»Bertha – das Ei ist hart!« Loriot
3
Systemhärtung
Vor der Inbetriebnahme im Internet muss ein Server ausreichend gehärtet werden. Das Internet ist ein gefährlicher Ort, in dem sich viele Spitzbuben tummeln, daher ist das Absichern eines Systems unabdingbar, um zu verhindern, dass das System von Angreifern kompromittiert wird. Es gibt verschiedene Motivationen für einen Angreifer. Ein neugieriger Hacker, den die Lust am Ausprobieren treibt und der keinen Schaden auf einem System anrichtet, ist der angenehmste Angreifer. Schlimmer sind destruktiv denkende und agierende Personen, die es darauf abgesehen haben, Systeme zu zerstören. Werden auf einem System sensible Daten verarbeitet und gespeichert, kann die Kompromittierung dieses Systems weitreichende Folgen haben – vom Imageverlust bis hin zu finanziellen oder rechtlichen Sanktionen. Ähnlich sieht es aus, wenn ein System kompromittiert und dann als Basis für weitere Angriffe genutzt wird. Kann der Betreiber des Systems dann nicht glaubhaft darlegen, dass er mit diesen weiteren Angriffen nichts zu tun hat, kann dies ernsthafte Konsequenzen nach sich ziehen, nicht erst seit der Einführung des so genannten Hackerparagraphen (§ 202c STGB) im letzten Jahr, der drakonische Strafen für Computerkriminalität vorsieht. Häufig werden kompromittierte Systeme auch als Spam-Relay oder Fileserver für so genannte Warez oder Schwarzkopien verwendet. Wenn der Betreiber dann einen Volumentarif beim Provider abgeschlossen hat, kann es sehr schnell ins Geld gehen, denn das Vorhandensein solcher Server spricht sich in der Szene sehr schnell herum, und sobald ein Server als Downloadserver bekannt ist, wird die verfügbare Bandbreite von den unzähligen »Kunden« bestmöglich ausgenutzt.
3.1
Inventur benötigter Dienste
Der erste Schritt zur Härtung eines Systems ist die Inventur der laufenden Prozesse und der Prozesse, die beim Systemstart geladen werden. Dabei sollte grundsätzlich die Regel gelten, dass nur solche Prozesse aktiv sein sollen, die für den
73
3
Systemhärtung
Betrieb benötigt werden. Nicht benötigte, aber trotzdem aktive Dienste haben die unangenehme Eigenschaft, leicht in Vergessenheit zu geraten und dadurch zu einem Sicherheitsrisiko zu werden. Auch können Dienste, die man »nur mal eben für die Installation« eingerichtet, anschließend aber nicht deaktiviert hat, später zu einem Problem werden. Das Problem an dieser Inventur ist, dass auf einem frisch installierten Linux-System in der Regel eine Vielzahl von Diensten aktiv sind, bei denen man nicht so genau weiß, welchem Zweck sie dienen und ob sie vom System benötigt werden. Auf einem ungehärteten Ubuntu-Server sind nach der Installation beispielsweise 52 Dienste aktiv. Die sicherste Methode, um die Dienste, die automatisch vom System gestartet werden und nicht abgeschaltet werden sollten, von den Diensten zu unterscheiden, die explizit durch entsprechende Startskripte geladen werden, ist das Untersuchen der entsprechenden Startskripte. Dazu ist es sinnvoll, die Startmechanismen der beiden in diesem Buch behandelten Distributionen kurz zu betrachten.
3.1.1
Systemstart Ubuntu
Traditionell startet ein Linux-System nach dem so genannten Sys-V-Bootkonzept. Sys-V ist die Abkürzung für System V, eine frühe Version von AT&T-Unix. Grundlage dieses Bootkonzeptes ist der Init-Prozess. Dieser wird als erster Prozess vom Kernel gestartet, nachdem dieser selbst vom Bootloader geladen wurde. Der InitProzess, der immer die Prozess-ID 1 besitzt, mounted die Dateisysteme und ist für das Starten aller folgenden Prozesse zuständig. Hierzu bedient er sich beim Sys-V-Bootkonzept der so genannten Runlevel. Ein Runlevel definiert einen bestimmten Status und wird mit einem eindeutigen Bezeichner gekennzeichnet. Der jeweilige Status eines Runlevels wird aus den Diensten bestimmt, die für diesen Runlevel gestartet bzw. angehalten werden. Oder andersrum: Für jeden Runlevel gibt es Anweisungen an den Init-Prozess, welche Dienste in diesem Runlevel gestartet oder gestoppt werden sollen. Runlevel 0 steht für das Herunterfahren eines Systems (alle Dienste werden angehalten), Runlevel 6 für einen Neustart (alle Dienste werden angehalten, und das System wird neu gestartet) und Runlevel S (alle Netzwerk- und Benutzerdienste werden angehalten) für den Single-User-Modus. Darüber hinaus verwenden die verschiedenen Linux-Distributionen die Runlevel 1 bis 5 recht unterschiedlich. Stand früher Runlevel 2 für den Betrieb ohne Netzwerk, Runlevel 3 für den Betrieb mit Netzwerk und Runlevel 5 für den Betrieb mit Netzwerk und X, arbeitet Ubuntu 8.04 beispielsweise standardmäßig im Runlevel 2. Die Festlegung, welcher Dienst in welchem Runlevel gestartet bzw. angehalten wird, geschieht über einfache Shell-Skripte und symbolische Links auf diese
74
Inventur benötigter Dienste
Skripte. Bei Ubuntu liegen die Skripte der Dienste im Verzeichnis /etc/init.d/. Das Vorhandensein eines Skriptes in diesem Verzeichnis bedeutet allerdings nicht, dass das betreffende Skript beim Systemstart ausgeführt wird. Erst ein symbolischer Link in das Verzeichnis des Runlevels, in dem das Skript ausgeführt werden soll, bringt das gewünschte Ergebnis. Hierzu gibt es unterhalb von /etc für jeden Runlevel, den das System kennt, ein eigenes Verzeichnis: # ls -d rc* rc0.d rc1.d
rc2.d
rc3.d
rc4.d
rc5.d
rc6.d
rc.local
rcS.d
Soll ein Dienst in einem bestimmten Runlevel gestartet werden, wird in dem jeweiligen Verzeichnis ein symbolischer Link auf das entsprechende Skript im Verzeichnis /etc/init.d angelegt. Dabei wird über ein Präfix festgelegt, ob das Skript gestartet (S) oder gestoppt (K) werden soll. Eine zweistellige Zahl zwischen 00 und 99 im Präfix gibt darüber hinaus einen relativen Zeitpunkt der Skriptausführung an. Um ein Skript zu starten, wird ihm der Parameter start übergeben, für das Stoppen der Parameter stop. Ein Init-Skript muss daher beide Parameter interpretieren können. Der symbolische Link … /etc/rc2.d/S89cron -> ../init.d/cron
… führt beim Wechsel in den Runlevel 2 das Skript /etc/init.d/cron mit dem Parameter start aus, startet also den Cron-Daemon. Das Skript … /etc/rc1.d/K11cron -> ../init.d/cron
… führt beim Wechsel in den Runlevel 1 das Skript /etc/init.d/cron mit dem Parameter stop aus, stoppt also den Cron-Daemon. Der durch die Zahlen 89 und 11 festgelegte Zeitpunkt der Skriptausführung ist nur relativ und bestimmt zwar die Reihenfolge der verschiedenen Skripte untereinander – ein Skript mit der Zahl 99 wird später ausgeführt als eins mit 01 –, berücksichtigt aber keine Abhängigkeiten von Diensten untereinander und ermöglicht auch keine dynamische Reaktion auf Ereignisse. Bei einem Server ist dies in der Regel unerheblich, aber auf einem Notebook beispielsweise ergibt es keinen Sinn, einen Netzwerkdienst zu starten, wenn kein Netzwerk vorhanden ist. Aus diesem Grund verwendet Ubuntu seit Edgy ein neues System, Upstart. Upstart ersetzt das alte Sys-V-Bootkonzept vollständig, das heißt, der Init-Prozess mit seiner zentralen Rolle als auch die starren Startskripte verlieren ihre Bedeutung. Die zentrale Steuerdatei des Init-Prozesses, die Datei /etc/inittab, sucht man unter Ubuntu daher auch vergeblich, ein untrügliches Indiz dafür, dass sich am Bootkonzept etwas geändert hat.
75
3.1
3
Systemhärtung
Dass die Sys-V-Skripte unter Ubuntu dennoch vorhanden sind, ist der Abwärtskompatibilität geschuldet, von Upstart benötigt werden sie nicht. Aus diesem Grund müssen auch beide Mechanismen betrachtet werden, wenn man die automatisch gestarteten Dienste kontrollieren möchte. Allein die herkömmlichen InitSkripte zu kontrollieren, reicht nicht aus, da »neue« Dienste unter Ubuntu schon von Upstart verwaltet werden – eine böse Falle für Härtungsmaßnahmen. Upstart arbeitet eventbasiert, das heißt, Dienste werden nicht starr nach einer festgelegten Reihenfolge gestartet, sondern dynamisch. Dabei können auch Abhängigkeiten definiert werden, um flexibel auf geänderte Rahmenbedingungen reagieren zu können. Leider ist die Dokumentation von Upstart immer noch sehr bescheiden, weswegen ich nach wie vor Init-Skripte verwende, um Dienste zu kontrollieren. Wichtig im Zusammenhang mit der Systemhärtung ist allerdings, die von Upstart verwalteten Dienste zu kontrollieren und zu prüfen, ob darunter solche vorhanden sind, die für den Serverbetrieb nicht benötigt werden. Dazu ist ein Blick in das Verzeichnis /etc/event.d notwendig, in dem die Upstart-Dienste definiert werden: # ls -la /etc/event.d/ insgesamt 92 drwxr-xr-x 2 root root 4096 2008-04-26 14:20 . drwxr-xr-x 140 root root 12288 2008-05-10 16:19 .. -rw-r--r-1 root root 260 2008-04-11 15:49 control-alt-delete -rw-r--r-1 root root 299 2008-04-11 15:49 logd -rw-r--r-1 root root 552 2008-04-11 15:49 rc0 -rw-r--r-1 root root 342 2008-04-11 15:49 rc1 -rw-r--r-1 root root 403 2008-04-11 15:49 rc2 -rw-r--r-1 root root 403 2008-04-11 15:49 rc3 -rw-r--r-1 root root 403 2008-04-11 15:49 rc4 -rw-r--r-1 root root 403 2008-04-11 15:49 rc5 -rw-r--r-1 root root 422 2008-04-11 15:49 rc6 -rw-r--r-1 root root 485 2008-04-11 15:49 rc-default -rw-r--r-1 root root 392 2008-04-11 15:49 rcS -rw-r--r-1 root root 575 2008-04-11 15:49 rcS-sulogin -rw-r--r-1 root root 558 2008-04-11 15:49 sulogin -rw-r--r-1 root root 306 2008-04-11 15:49 tty1 -rw-r--r-1 root root 300 2008-04-11 15:49 tty2 -rw-r--r-1 root root 300 2008-04-11 15:49 tty3 -rw-r--r-1 root root 300 2008-04-11 15:49 tty4 -rw-r--r-1 root root 300 2008-04-11 15:49 tty5 -rw-r--r-1 root root 300 2008-04-11 15:49 tty6
Jede Datei ist für einen bestimmten Dienst zuständig. Ins Auge fällt sofort die Datei control-alt-delete. In dieser wird definiert, dass das Drücken der Tastenkombination (Strg)+(Alt)+(Entf) zum Neustart des Systems führt. Da dies insbesondere bei einem Server mehr als überflüssig ist, sollte diese Datei gelöscht wer-
76
Inventur benötigter Dienste
den. Ein Neustart des Upstart-Daemons ist nach Änderungen an den DienstDateien nicht notwendig, da der Daemon Änderungen am Verzeichnis /etc/ event.d überwacht und die darin enthaltenen Dateien bei einer Änderung selbständig neu einliest. Interessant in diesem Verzeichnis sind die Dateien rc*, da über diese die Kompatibilität zum alten Sys-V-Bootkonzept erreicht wird. Der Upstart-Daemon wird über die Dateien angewiesen, die entsprechenden Skripte in den betreffenden Runlevel-Verzeichnissen auszuführen. Solange dies noch der Fall ist und solange sich die Dokumentation von Upstart nicht gebessert hat, kann das Sys-V-Bootkonzept mit seinen Init-Skripten getrost beibehalten werden. Ein Server benötigt selten eventgesteuerte Dienste, da sich die Umgebung selten ändert. Überdies sollte man als Serverbetreiber immer konservativ denken und auf bewährte Technologien setzen, bevor man sich in neue Abenteuer stürzt. Für die Zukunft bleibt ohnehin abzuwarten, ob sich Upstart wirklich durchsetzen kann oder ob der Kompatibilitätsmodus zum Sys-V-Bootkonzept einen breiten Wechsel zum neuen Konzept nicht eher verhindert als erleichtert. Wer tauscht schon ohne Zwang freiwillig ein bewährtes Konzept gegen ein neues aus …
3.1.2
Systemstart Gentoo
Gentoo geht einen etwas anderen Weg, um das Bootkonzept flexibler zu gestalten. Dabei wird das bewährte Konzept der Runlevel nicht aufgegeben, sondern durch einen eigenen Mechanismus um die Fähigkeiten erweitert, Abhängigkeiten zwischen Diensten zu definieren. Die von Init zu startenden Dienste befinden sich bei Gentoo – ebenso wie bei Ubuntu – im Verzeichnis /etc/init.d. Die Zuordnung, welcher Dienst in welchem Runlevel gestartet wird, geschieht allerdings nicht über entsprechend benannte rc-Verzeichnisse unterhalb von /etc, sondern über Verzeichnisse mit kanonischen Namen unterhalb von /etc/runlevels: [12:02:28] --- kr@gentoo:/etc/runlevels # ls -la total 24 drwxr-xr-x 6 root root 4096 May 1 20:51 drwxr-xr-x 34 root root 4096 May 11 10:46 drwxr-xr-x 2 root root 4096 May 1 20:51 drwxr-xr-x 2 root root 4096 May 1 20:51 drwxr-xr-x 2 root root 4096 May 1 20:51 drwxr-xr-x 2 root root 4096 May 1 20:51
. .. boot default nonetwork single
Diese Verzeichnisse enthalten die für den jeweiligen Runlevel benötigten InitSkripte, die selbst wiederum symbolische Links auf die in /etc/init.d enthaltenen
77
3.1
3
Systemhärtung
Skripte sind. Im Verzeichnis /etc/conf.d befinden sich dienstspezifische Konfigurationsdateien, mit denen Optionen für die einzelnen Dienste festgelegt werden können. Der Init-Prozess wird über die Datei /etc/inittab konfiguriert, in der die verschiedenen Runlevel definiert sind und über die auch der Standard-Runlevel festgelegt wird: l0:0:wait:/sbin/rc shutdown l1:S1:wait:/sbin/rc single l2:2:wait:/sbin/rc nonetwork l3:3:wait:/sbin/rc default l4:4:wait:/sbin/rc default l5:5:wait:/sbin/rc default l6:6:wait:/sbin/rc reboot [...] id:3:initdefault:
Abgesehen von der geänderten Verzeichnisstruktur und den kanonischen Bezeichnungen für die Runlevel, die im Gegensatz zu den klassischen Sys-V-Bezeichnern aus Ziffern oder Buchstaben für den Benutzer lediglich eine kosmetische Verbesserung darstellen, unterscheidet sich das Bootkonzept von Gentoo bis hierher noch nicht vom Sys-V-Bootkonzept. Interessant wird das Bootkonzept von Gentoo durch das Format der Init-Skripte. Zusätzlich zu den Standard-Aufrufparametern start und stop gibt es unter Gentoo noch weitere Parameter. Die folgende Tabelle führt die möglichen Parameter eines Init-Skriptes unter Gentoo auf. Aufrufparameter
Bedeutung
start
Startet den Dienst und alle Dienste, von denen dieser Dienst abhängt.
stop
Hält den Dienst und alle von ihm abhängenden Dienste an.
restart
Führt nacheinander start und stop aus.
condrestart
Führt ein restart aus, wenn der Dienst bereits aktiv ist.
pause
Hält den Dienst an, nicht aber die Dienste, die von diesem Dienst abhängen.
zap
Ein als aktiv laufender Dienst, der bereits beendet ist, wird mit zap als gestoppt markiert.
reload
Einlesen der Konfigurationsdateien, ohne den Dienst zu beenden (kill -HUP). Abhängig von der Implementierung des jeweiligen Dienstes.
Tabelle 3.1 Aufrufparameter eines Init-Skriptes unter Gentoo
78
Inventur benötigter Dienste
Aufrufparameter
Bedeutung
status
Zeigt an, ob ein Dienst gestartet oder gestoppt ist.
ineed
Zeigt alle Dienste, von denen der Dienst abhängt.
iuse
Zeigt alle Dienste, die der Service verwendet, zum Betrieb aber nicht benötigt.
needsme
Zeigt alle Dienste, die von dem Dienst abhängen.
usesme
Analog zu iuse: Zeigt alle Dienste, die diesen Dienst verwenden, für den Betrieb aber nicht benötigen.
broken
Führt alle nicht erfüllten Abhängigkeiten von oder zu diesem Dienst auf.
help
Zeigt eine Hilfedatei zum Dienst.
Tabelle 3.1 Aufrufparameter eines Init-Skriptes unter Gentoo (Forts.)
Die Aufrufparameter zeigen, dass Dienste miteinander verknüpft werden können. Im Allgemeinen ist es beispielsweise wenig sinnvoll, einen Netzwerkdienst zu aktivieren, wenn nicht mindestens ein Netzwerk-Interface gestartet worden ist. Realisiert wird diese gegenüber dem ursprünglichen Sys-V-Bootkonzept erweiterte Funktionalität über ein eigenes Format der Init-Skripte. In jedem InitSkript gibt es neben den entsprechenden Handlern für die obenstehenden Aufrufparameter einen Abschnitt depend(), in dem die Abhängigkeiten des Dienstes beschrieben werden. Dabei können über die in der folgenden Tabelle aufgeführten Schlüsselwörter Abhängigkeiten und Reihenfolge definiert werden. Schlüsselwort
Bedeutung
use
Der angegebene Dienst wird verwendet, aber nicht benötigt.
need
Der angegebene Dienst wird benötigt.
provide
Dieser Dienst steht unter dem angegebenen Namen für andere Dienste zur Verfügung.
after
Der Dienst muss nach dem angegebenen Dienst gestartet werden.
before
Der Dienst muss vor dem angegebenen Dienst gestartet werden.
Tabelle 3.2 Schlüsselwörter für Init-Skripte unter Gentoo
Für den oben bereits als Beispiel verwendeten SSH-Dienst sieht der entsprechende Eintrag in seinem Init-Skript wie folgt aus: depend() { use logger dns need net }
Der SSH-Dienst verwendet also die Dienste logger und dns und benötigt den Dienst net. Das heißt, dass er ohne logger und dns startet, ohne net aber nicht. Dies
79
3.1
3
Systemhärtung
lässt sich mit den bereits erwähnten Aufrufparametern des Init-Skriptes überprüfen: # /etc/init.d/sshd iuse syslog-ng
Dass hier der Dienst dns nicht aufgeführt wird, liegt daran, dass er nicht installiert ist. Das ist nicht weiter dramatisch, da der Dienst ja nur verwendet, nicht aber benötigt wird. # /etc/init.d/sshd ineed net
Der Dienst net wird in der Tat benötigt. Umgekehrt weiß auch der Dienst net, dass sshd ihn benötigt: # /etc/init.d/net.eth0 needsme mit-krb5kadmind mit-krb5kdc netmount slapd slurpd sshd net
3.1.3
Abspecken
Zum Hinzufügen und Löschen von Diensten, die beim Systemstart automatisch gestartet werden, gibt es unter Ubuntu und unter Gentoo jeweils ein eigenes Programm. Da die zu startenden Dienste lediglich über Dateien bzw. symbolische Links definiert werden, können eben diese Dateien und Symlinks auch händisch manipuliert werden. Die Verwendung der dafür vorgesehenen Tools ist aber weniger fehlerträchtig und sollte daher dem Old-School-Vorgehen vorgezogen werden. Nicht benötigte Dienste und Pakete sollten grundsätzlich vom System gelöscht und nicht nur deaktiviert werden. Der Grund liegt zum einen darin, dass die Anzahl der möglichen Schwachstellen eines Systems proportional zur Anzahl der installierten Softwarepakete wächst. Je mehr Software installiert ist, desto mehr Möglichkeiten für sicherheitskritische Softwarefehler gibt es. Zum anderen hat installierte, aber nicht verwendete Software die unangenehme Eigenschaft, schnell in Vergessenheit zu geraten. Dadurch verliert ein Systemadministrator leicht den Überblick über mögliche Angriffsvektoren gegen sein System, denn wer sein System nicht kennt, weiß auch nicht, an welchen Stellen es verwundbar ist. Zwar werden sowohl Ubuntu als auch Gentoo regelmäßig mit Sicherheitsupdates versorgt, so dass Softwarefehler in der Regel behoben werden, allerdings gilt dies nur für bekannte Softwarefehler. Darüber hinaus gibt es immer eine gewisse Zeitspanne zwischen dem Bekanntwerden einer Sicherheitslücke, der Veröffentlichung eines Updates durch den Distributor und dem Einspielen dieses Updates durch den Administrator.
80
Inventur benötigter Dienste
Noch gefährlicher wird die Kombination aus beiden Faktoren: Der Administrator vergisst, dass eine bestimmte Software installiert ist – da diese Software nicht verwendet wird und nur »per Zufall« auf das System gekommen ist –, und installiert verfügbare Sicherheitsupdates für diese Software nicht. Aus diesem Grund sollte ein System grundsätzlich so schlank wie möglich gehalten werden. Insbesondere gilt dies für Entwicklerwerkzeuge und Programme zur Netzwerkanalyse. Auf einem Produktivsystem haben Compiler, Debugger, Portscanner und artverwandte Programme nichts zu suchen. Gelingt es einem Angreifer, ein System zu kompromittieren, auf dem solche Pakete installiert sind, kann er mit den Entwicklerwerkzeugen leicht eigene Programme kompilieren. Mit Programmen wie einem Portscanner oder einem Netzwerksniffer kann er das kompromittierte System leicht als Ausgangsbasis für weitere Angriffe verwenden. Selbst wenn Programme dieser Art in einer Aufbau- und Testphase benötigt werden, sollten sie vor dem Übergang in den Produktivbetrieb unbedingt entfernt werden. Ubuntu Unter Ubuntu muss das Starten von Diensten – wie in Abschnitt 3.1.1 beschrieben – an zwei Stellen kontrolliert werden. Im ersten Schritt werden die im Verzeichnis /etc/event.d konfigurierten Dienste überprüft. In der Standardkonfiguration sollte dort die Datei control-alt-delete entfernt werden. Einen automatischen Neustart des Systems durch das Drücken einer Tastenkombination auszulösen, ist für ein Desktopsystem schon eine gefährliche Sache, bei einem Server sollte dies grundsätzlich deaktiviert werden. Auf einem Server sollten keine administrativen Aktionen – zu solchen zählt auch ein Neustart – ohne Anmeldung eines Benutzers möglich sein. Im zweiten Schritt steht die Inventur der Init-Dienste an. Für das Einrichten von Init-Skripten gibt es unter Ubuntu das Programm update-rc.d aus dem Paket sysv-rc. Darüber hinaus steht mit dem Programm sysv-rc-conf eine grafische Möglichkeit zur Verwaltung von Init-Skripten zur Verfügung. Grafik ist in diesem Zusammenhang etwas hochgegriffen, es handelt sich um ASCII-Darstellung auf der Konsole. Für dieses Programm muss also keine grafische Oberfläche installiert werden. Abbildung 3.1 zeigt die Oberfläche von sysv-rc-config. Innerhalb dieser Oberfläche kann man mit den Pfeiltasten navigieren und durch Drücken der (Leertaste) einen Dienst in einem bestimmten Runlevel aktivieren oder deaktivieren. Beim Verlassen des Programms mit der Taste (Q) werden automatisch die entsprechenden symbolischen Links in den rc-Verzeichnissen erstellt bzw. gelöscht.
81
3.1
3
Systemhärtung
Abbildung 3.1
Init-Skripte komfortabel aktivieren oder deaktivieren
Flexibler, dafür aber nicht so übersichtlich, ist das Programm update-rc.d. Es erlaubt das Anlegen und Löschen von Init-Skripten über die Kommandozeile. Voraussetzung dafür ist, dass ein für den einzurichtenden Dienst passendes InitSkript im Verzeichnis /etc/init.d vorhanden ist. Die Verwendung von update-rc.d zeigt das folgende Beispiel. Um herauszufinden, in welchem Runlevel sich das Ubuntu-System standardmäßig befindet, wird der Befehl runlevel verwendet, der den vorherigen und den aktuellen Runlevel anzeigt: # runlevel N 2
Das N in der ersten Spalte der Ausgabe gibt an, dass sich das System vor dem aktuellen Runlevel in keinem anderen Runlevel befunden hat. Dies klingt plausibel, da das System frisch gebootet worden ist. Die zweite Spalte gibt den aktuellen Runlevel an. Das System startet offensichtlich standardmäßig im Runlevel 2. Daher sollte das Verzeichnis /etc/rc2.d nach überflüssigen Diensten durchsucht werden: # ls /etc/rc2.d/ README S11klogd S10sysklogd S16openvpn
S16ssh S20rsync
S89atd S89cron
S99rc.local S99rmnologin
Die Datei README enthält eine Anleitung zum Anlegen neuer Verknüpfungen (siehe Abschnitt 3.1.1). Ins Auge fallen die Einträge S20rsync und S16openvpn. Der rsync-Daemon wird zum Synchronisieren von Verzeichnissen und Dateien
82
Inventur benötigter Dienste
verschiedener Rechner benötigt, muss aber nicht explizit laufen, da rsync auch ohne Daemon über SSH erfolgen kann. OpenVPN ist eine VPN-Lösung, die auf dem Server aber nicht verwendet wird, daher kann auch dieser Dienst entfernt werden. Dazu wird das Programm update-rc.d mit dem Parameter -f, dem Namen des zu entfernenden Dienstes und dem Parameter remove aufgerufen. Der Parameter -f dient dazu, die symbolischen Links in allen rc-Verzeichnissen zu entfernen, auch wenn das eigentliche Init-Skript in /etc/init.d noch vorhanden ist. # update-rc.d -f openvpn remove Removing any system startup links for /etc/init.d/openvpn ... /etc/rc0.d/K80openvpn /etc/rc1.d/K80openvpn /etc/rc2.d/S16openvpn /etc/rc3.d/S16openvpn /etc/rc4.d/S16openvpn /etc/rc5.d/S16openvpn /etc/rc6.d/K80openvpn
Das Gleiche wird für den rsync-Daemon auch durchgeführt: # update-rc.d -f rsync remove Removing any system startup links for /etc/init.d/rsync ... /etc/rc1.d/K20rsync /etc/rc2.d/S20rsync /etc/rc3.d/S20rsync /etc/rc4.d/S20rsync /etc/rc5.d/S20rsync
Bitte beachten Sie, dass damit nur die Verknüpfungen entfernt worden sind, mit denen die beiden Dienste gestartet werden. Die Dienste selbst und alle Dateien, die dazugehören, wurden nicht deinstalliert. Dies sollte im Rahmen der Systemhärtung zwar auch geschehen, allerdings sollte jetzt erst die Funktionsfähigkeit des Systems überprüft werden. Das heißt, das System sollte nach dem Entfernen der Startverknüpfungen aller vermeintlich überflüssigen Dienste neu gestartet werden, um zu sehen, ob auch ein für das System notwendiger Dienst deaktiviert worden ist. Ist dies der Fall, kann der betreffende Dienst über update-rc.d wieder eingerichtet werden. Hierzu gibt es die Möglichkeit, Standard-Einstellungen zu verwenden … # update-rc.d openvpn defaults Adding system startup for /etc/init.d/openvpn ... /etc/rc0.d/K20openvpn -> ../init.d/openvpn /etc/rc1.d/K20openvpn -> ../init.d/openvpn /etc/rc6.d/K20openvpn -> ../init.d/openvpn
… oder Runlevel und Priorität selbst festzulegen: # update-rc.d openvpn start 99 2 3 . stop 01 1 6 0 . Adding system startup for /etc/init.d/openvpn ... /etc/rc0.d/K01openvpn -> ../init.d/openvpn /etc/rc1.d/K01openvpn -> ../init.d/openvpn /etc/rc6.d/K01openvpn -> ../init.d/openvpn /etc/rc2.d/S99openvpn -> ../init.d/openvpn /etc/rc3.d/S99openvpn -> ../init.d/openvpn
Sofern das System nach einem Neustart noch so läuft wie geplant, sollten die nicht benötigten Dienste und Programmpakete deinstalliert werden. Dabei hilft das Anfertigen einer Liste aller installierten Pakete mit dpkg (siehe Abschnitt »dpkg« auf Seite 55). Viele der vorhandenen Pakete sind über Abhängigkeitsprüfungen installiert worden und können nicht ohne Gefahr deinstalliert werden. Die Prüfung der Liste sollte daher mit Sorgfalt durchgeführt werden, um das System nicht durch Deinstallieren wichtiger Pakete unbenutzbar zu machen (aptget gibt aber auch eine entsprechende Warnung aus). Eine frische Installation eines Ubuntu-Servers ist erfreulich schlank, d. h., das Sichten der installierten Pakete geht schnell vonstatten. Im Fall der Beispielinstallation muss lediglich das Paket openvpn deinstalliert werden: # apt-get purge openvpn Paketlisten werden gelesen... Fertig Abhängigkeitsbaum wird aufgebaut Reading state information... Fertig Die folgenden Pakete werden ENTFERNT: openvpn* 0 aktualisiert, 0 neu installiert, 1 zu entfernen und 0 nicht aktualisiert. After this operation, 1077kB disk space will be freed. Möchten Sie fortfahren [J/n]? j (Lese Datenbank ... 20806 Dateien und Verzeichnisse sind derzeit installiert.) Entferne openvpn ... * Stopping virtual private network daemon. [ OK ] Lösche Konfigurationsdateien von openvpn ...
84
Inventur benötigter Dienste
Gentoo Die Verwaltung von Init-Skripten ist unter Gentoo dank der Programme rc-config, rc-update und rc-status sehr komfortabel. rc-status gibt verschiedene Informationen über Runlevel und konfigurierte Dienste aus. Der Schalter -l zeigt eine Liste der vorhandenen Runlevel an: # rc-status -l boot default nonetwork single
Der Schalter -a gibt eine Liste aller konfigurierten Dienste aus. Ohne Schalter aufgerufen, zeigt rc-update den Status aller Dienste des aktuellen Runlevels: # rc-status Runlevel: default hdparm local net.eth0 netmount sshd syslog-ng vixie-cron
[ [ [ [ [ [ [
started started started started started started started
] ] ] ] ] ] ]
Das Programm rc-config gibt weitergehende Informationen über Init-Skripte aus, beispielsweise eine Liste der verfügbaren Skripte samt der Verwendung in den jeweiligen Runleveln: # rc-config list Available init scripts bootmisc checkfs checkroot clock consolefont crypto-loop gpm hdparm hostname keymaps local localmount mit-krb5kadmind mit-krb5kdc modules
Darüber hinaus können mit rc-config auch mehrere Dienste auf einmal bedient werden. Eine Liste der Status der im aktuellen Runlevel konfigurierten Dienste gibt rc-config show aus: # rc-config show Status of init scripts in runlevel default hdparm [started] local [started] net.eth0 [started] netmount [started] sshd [started] syslog-ng [started] vixie-cron [started]
Um z. B. die Dienste hdparm und vixie-cron anzuhalten, wird rc-config mit den entsprechenden Parametern aufgerufen: # rc-config pause hdparm vixie-cron Pausing init scripts * Stopping vixie-cron ...
Der hdparm-Daemon gibt keine Rückmeldung aus, weswegen rc-config auch nur den Status von vixie-cron ausgibt. Ein erneutes Anzeigen der Dienste lässt erkennen, dass beide Dienste angehalten wurden: # rc-config show Status of init scripts in runlevel default hdparm [stopped] local [started] net.eth0 [started] netmount [started] sshd [started]
86
Inventur benötigter Dienste
syslog-ng vixie-cron
[started] [stopped]
Um beide Dienste zu starten, wird der eben verwendete Aufruf mit dem Parameter start statt stop aufgerufen: # rc-config start hdparm vixie-cron Starting init scripts * Running hdparm on /dev/hdc ... * Starting vixie-cron ...
Das Pendant zu update-rc.d unter Ubuntu ist bei Gentoo rc-update. Damit können vorhandene Init-Skripte für Runlevel aktiviert oder deaktiviert werden. Auch hier gibt es einen Standard-Modus, der den angegebenen Dienst im Standard-Runlevel installiert bzw. aus diesem löscht: # rc-update -d hdparm default * 'hdparm' removed from the following runlevels: default # rc-update -a hdparm default * hdparm added to runlevel default
Über die Angabe konkreter Runlevel kann ein Dienst darüber hinaus auch in Nicht-Standard-Runleveln aktiviert oder gelöscht werden. Im Gegensatz zu Ubuntu ist allerdings in beiden Modi keine Angabe einer Zahl zur Festlegung innerhalb der Start- oder Stoppreihenfolge notwendig, da die Startreihenfolge der Dienste bei Gentoo ja über die in den Init-Skripten festgelegten Abhängigkeiten geregelt wird. Die Minimalinstallation von Gentoo ist so schlank, dass keine Dienste deaktiviert werden müssen. Trotzdem ist eine regelmäßige Inventur der installierten Dienste angezeigt. Hilfreich dafür ist das Programm eix. Es ist nicht Bestandteil der Minimalinstallation und muss daher händisch installiert werden: emerge eix
Nach der Installation muss eix die lokale Portage-Datenbank einlesen. Dies geschieht über den Befehl update-eix. Anschließend können Informationen über die installierten Pakete abgerufen werden: # eix -I [...]
Dabei zeigt eix nicht nur die installierten Pakete, sondern gibt direkt an, ob für diese Pakete Updates verfügbar sind. Zu erkennen ist dies über das Kürzel U in der ersten Spalte. Die Zeile Available versions enthält dann Angaben zu den verfügbaren Updates.
87
3.1
3
Systemhärtung
[I] x11-proto/xextproto Available versions: Installed versions: Homepage: Description:
Für die Inventur der installierten Pakete gilt das bereits oben Gesagte: Nur für den Betrieb notwendige Pakete sollten installiert sein, Entwicklungswerkzeuge und Netzwerkanalyse-Programme sollten grundsätzlich auf keinem produktiven Server vorhanden sein. Ist ein zu deinstallierendes Paket identifiziert, kann es mit emerge --unmerge vom System entfernt werden.
3.1.4
Netzwerkdienste kontrollieren
Besondere Aufmerksamkeit bei der Inventur der installierten und aktiven Dienste gehört natürlich den Netzwerkdiensten, also Programmen, die über das Netzwerk erreichbar sind, da dies der sinnvollste Weg für einen Angreifer ist, einen Server zu kompromittieren. Neben der Überprüfung der Paketliste ist ein Blick auf die aktiven Netzwerkdienste sinnvoll, da nicht jeder Paketname so aussagekräftig ist, um daraus auf einen Netzwerkdienst schließen zu können. Eine Übersicht über die aktiven Netzwerkdienste unter Linux gibt – distributionsübergreifend – der Befehl netstat. Mit dem Parameter -tulpn zeigt netstat alle Netzwerkdienste für TCP (t), UDP (u), ohne Namensauflösung (n) und inklusive des Prozessnamens des jeweiligen Dienstes (p). # netstat -tulpn Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address State PID/Program name tcp 0 0 127.0.0.1:631 LISTEN 5543/cupsd tcp6 0 0 :::22 LISTEN 4204/sshd
Foreign Address 0.0.0.0:* :::*
Auf diesem System ist also ein cups-Daemon – ein Druckdienst – aktiv, der auf dem lokalen Loopback-Interface (127.0.0.1) auf TCP-Port 631 lauscht. Darüber hinaus lauscht auf allen Interfaces der SSH-Daemon auf TCP-Port 22. Da der cupsDaemon nur auf dem lokalen Loopback-Interface lauscht, ist er aus dem Netz-
88
Inventur benötigter Dienste
werk nicht erreichbar. Ob dieser Dienst für das System notwendig ist, hängt vom Anforderungsprofil des Servers ab. Für einen Druckerserver lässt sich die Frage bejahen, ein Web- oder Mailserver im Internet benötigt mit Sicherheit keinen Druckdienst. Nach Prüfen der Anforderung sollte in diesem Beispiel der cupsDienst daher gegebenenfalls deaktiviert und deinstalliert werden. Allgemein sollten alle Netzwerkdienste, die mit netstat als aktiv erkannt worden sind und nicht benötigt werden, deaktiviert und deinstalliert werden. Sofern Netzwerkdienste benötigt, aber nicht aus von außen erreichbar sein müssen, sollten sie so konfiguriert werden, dass sie nur auf dem lokalen Loopback-Interface erreichbar sind. In Kapitel 4, »Serverdienste«, wird dies an den Beispielen MySQL und PostgreSQL gezeigt.
3.1.5
Berechtigungen prüfen
In Abschnitt 2.3.5 wurde bereits die Wichtigkeit einer ausreichend restriktiv gesetzten Umask erläutert. Leider wirkt sich das Setzen der Umask nur auf alle Dateisystem-Operationen aus, die nach diesem Zeitpunkt stattfinden. Die Zugriffsrechte bereits vorhandener Dateien und Verzeichnisse werden dadurch allerdings nicht verändert. Das bedeutet, dass man alle Dateien und Verzeichnisse, die man vor der Anpassung der Umask bereits erstellt oder auf das System kopiert hat, einer kritischen Prüfung hinsichtlich ihrer Zugriffsrechte unterziehen sollte. Typische Kandidaten für falsch gesetzte Zugriffsrechte sind Datenverzeichnisse von Webservern. Diese werden häufig von Test- und Entwicklungssystemen auf einen Server kopiert, wobei das Anpassen von Zugriffsrechten dann leider vergessen wird. Dies ist umso kritischer, als sich mitunter sensible Dateien in solchen Verzeichnissen befinden, wie z. B. Passwort-Repositories von ApplicationServern, htaccess-Dateien des Apache-Webservers mit Benutzerpasswörtern, Konfigurationsdateien für Datenbanken inklusive Zugangsdaten etc. Bei kleinen Datenbeständen ist das Überprüfen der Zugriffsrechte schnell erledigt, bei großen Datenbeständen hingegen kann das manuelle Überprüfen zu einer Sisyphosarbeit ausarten. Wer kann schon Tausende von Dateien und Verzeichnissen auf korrekt gesetzte Zugriffsrechte überprüfen? In solchen Fällen hilft das gezielte Suchen nach kritischen Dateien mit entsprechenden Befehlen. # find ./ -name '*pass*' -type f ./pam.d/passwd ./pam.d/common-password ./passwd./security/opasswd ./passwd
89
3.1
3
Systemhärtung
Der vorstehende Befehl sucht im aktuellen Pfad nach allen Dateien, bei denen die Buchstaben »pass« im Namen vorkommen. Die Beschränkung auf Dateien ist sinnvoll, da dies bei einem Verzeichnisbaum mit vielen Verzeichnissen den Suchvorgang merklich beschleunigen kann. Weitere Suchvariationen sind die folgenden: # find ./ -name '*htaccess*' -type f
Mit diesem Befehl werden htaccess-Dateien gesucht. Je nach gewünschter Suche kann das Suchmuster natürlich beliebig variiert und angepasst werden. Wichtig ist die Verwendung von Wildcards (*), da auch die Sicherheitskopie einer Passwortdatei sensible Daten enthalten kann. Wenn Sie dann genau nach ».htpasswd« suchen, die Datei aber als htpasswd-bak gespeichert ist, übersehen Sie sie. Neben der Suche nach Dateinamen ist die Suche nach Dateien mit offensichtlich nicht sinnvoll gesetzten Rechten möglich. Um alle Dateien im aktuellen Verzeichnis (und in denen darunter) zu finden, bei denen alle Benutzer lesenden und schreibenden Zugriff besitzen, hilft auch find: find ./ -type f -perm 666
Das Gleiche für Verzeichnisse: find ./ -type d -perm 777
Um alle Dateien des aktuellen Verzeichnisses rekursiv auf 600 zu setzen – analog zur Umask 077 –, kann auch find verwendet werden: find ./ -type f -exec chmod 600 {} \;
Auch hier wieder das Gleiche für Verzeichnisse: find ./ -type d -exec chmod 700 {} \;
Neben falsch gesetzten Zugriffsrechten sollten auch die Besitzrechte an Dateien und Verzeichnissen überprüft werden. Datenverzeichnisse für Webserver beispielsweise gehören in der Regel dem Benutzer, unter dem der Webserver-Prozess läuft. Ein simples … chown -R <user>:
… führt die entsprechende Zuweisung aus. Dateien und Verzeichnisse, die keinem gültigen Benutzer oder keiner gültigen Benutzergruppe gehören, offenbart auch wieder find: # find / -nogroup # find / -nouser
90
Inventur benötigter Dienste
Interessant ist die Überprüfung der Eigentumsrechte aber nicht nur bei eigenen Datenverzeichnissen, sondern auch bei den Daten des Betriebssystems. Zwar sind Ubuntu und Gentoo von Hause aus schon recht sicher konfiguriert, aber Kontrolle ist besser als Vertrauen. Prüfen Sie daher nicht nur die eigenen Daten. Insbesondere Programme, welche die Attribute setuid und setguid gesetzt haben, also für die Ausführung das Benutzerkonto des aufrufenden Benutzers oder der aufrufenden Gruppe erhalten, sollten mit Skepsis betrachtet werden. Ein Programm, das über setuid mit Root-Rechten läuft, aber für normale Benutzer beschreibbar ist, stellt ein enormes Sicherheitsrisiko dar. Der folgende Befehl gibt alle Programme aus, bei denen setuid gesetzt ist: # find / -perm +4000
Der folgende Befehl gibt alle Programme aus, bei denen setguid gesetzt ist: # find / -perm +2000
Achten Sie insbesondere darauf, dass Serverprozesse keine Systemdateien lesen oder schreiben dürfen. Wird ein solcher Dienst kompromittiert, kann ein Angreifer darüber Manipulationen am Betriebssystem vornehmen und dieses dadurch beschädigen oder sich auf diese Weise erweiterten Zugriff auf das System verschaffen.
3.1.6
Virenschutz
Das Thema Virenschutz ist in der Linux-Welt nach wie vor ein Nischenthema. Es existieren verschiedene freie und kommerzielle Antiviren-Lösungen, allerdings ist bis heute kein ernstzunehmender Virus für Linux in freier Wildbahn gesichtet worden. Das mag an der Inhomogenität der Plattform liegen, aber auch daran, dass Linux hauptsächlich auf Servern zum Einsatz kommt und es dort weniger Angriffsmöglichkeiten für Viren gibt als auf Desktopsystemen, die von mehr oder weniger aufmerksamen Benutzern bedient und verwaltet werden. Darüber hinaus ist die Gefahr des unbemerkten Einschleusens von Schadsoftware durch eine stringente Trennung von Benutzer- und Administrationsaufgaben, wie es unter Linux sein sollte, wesentlich geringer als beispielsweise bei den Windows-Versionen der Vor-Vista-Ära. Bei diesen Versionen verfügt jeder Benutzer standardmäßig über administrative Rechte, was zur Folge hat, dass Schadsoftware, die über ein solches Benutzerkonto eingeschleust wird – sei es durch infizierte E-Mail-Anhänge oder dubiose Internetseiten etc. –, das jeweilige System vollständig kompromittieren kann. Antiviren-Lösungen für Linux werden in der Regel nicht zum Schutz der LinuxSysteme selbst verwendet, sondern beispielsweise um Content, der auf einem solchen Server abgelegt wird, auf Schadsoftware zu überprüfen, so dass keine mit
91
3.1
3
Systemhärtung
Schadsoftware infizierte Software weitergegeben wird. Wenn Sie beispielsweise auf einer Webseite eine Uploadmöglichkeit für Dateien anbieten, die andere Benutzer herunterladen können, wäre es ein guter Dienst am Kunden, die hochgeladenen Dateien auf Schadsoftware zu überprüfen, um eine Verbreitung über Ihre Webseite zu verhindern. Das Problem bei den für Linux verfügbaren Antiviren-Lösungen ist, dass diese nur recht wenig Schadsoftware erkennen, mit entsprechenden Lösungen für Windows also nicht mithalten können. Des Weiteren ergibt sich beim Einsatz einer solchen Lösung noch ein ganz anderes Problem. Wie in Abschnitt 3.1.3 beschrieben, erhöht jeder installierte und aktive Dienst die Gefahr eines Softwarefehlers und damit einer Sicherheitslücke. Das bedeutet, dass ein Angreifer z. B. über eine manipulierte Datei eine Sicherheitslücke in einem Virenscanner ausnutzen und damit einen Server kompromittieren kann. Der quelloffene Virenscanner ClamAV wies erst unlängst in der Version 0.92 eine Sicherheitslücke auf, über die ein Angreifer einen Heap-Overflow auf dem Zielsystem provozieren und dadurch Code auf dem System ausführen konnte. Dies ist für einen Serverbetreiber eine groteske Situation: Eine Software, die Sicherheit erhöhen soll, stellt ein Einfallstor für Angreifer dar. Zusammenfassend lässt sich zu Antiviren-Lösungen unter Linux sagen, dass die beschränkte Wirksamkeit keine ausreichende Rechtfertigung für die Gefahr ist, die man sich durch eine solche Software auf das System holt. Im Regelfall ist ein Virenscanner auf einem Webserver ohnehin überflüssig.
3.2
Host-Firewall
Nachdem das System mit den oben beschriebenen Maßnahmen gehärtet worden ist, sollte noch die Absicherung der Netzwerkseite folgen. Das Abschalten nicht benötigter Netzwerkdienste ist der erste Schritt, der zweite Schritt ist das Einrichten einer Firewall auf dem Server. An dieser Stelle kommt häufig die Frage nach dem Sinn einer solchen Firewall auf, da doch ohnehin alle nicht benötigten Dienste abgeschaltet sind. Dies ist grundsätzlich richtig, aber Administrationsaufgaben haben die unangenehme Eigenschaft, mitunter nicht geplante Nebeneffekte zu verursachen. So kann durch das Installieren eines benötigten Paketes über automatische Abhängigkeiten ein weiteres Paket installiert werden, das einen Netzwerkdienst startet und auf diese Weise eine Zugriffsmöglichkeit auf das System öffnet. Hand aufs Herz: Wer kontrolliert schon alle automatisch über Abhängigkeiten installierten Pakete daraufhin, ob sie Netzwerkdienste mitbringen?
92
Host-Firewall
Eine Firewall, die nur Verbindungen zu genau definierten und für den Betrieb benötigten Ports zulässt, beugt dem Gefahrenpotential durch unbeabsichtigt und unbemerkt gestartete Netzwerkdienste vor. Darüber hinaus gilt für den Netzwerkverkehr dasselbe wie für die Konfiguration des gesamten Systems: Es sollte nur benötigter Netzwerkverkehr zum System möglich sein. Software hat die unangenehme Eigenschaft, niemals fehlerfrei zu sein, wobei die Fehlerwahrscheinlichkeit mit dem Umfang der Software wächst. So kann auch der TCP-Stack von Linux Sicherheitslücken aufweisen. Das Einschränken des Netzwerkverkehrs durch eine Firewall verringert die Wahrscheinlichkeit, dass ein Fehler im TCPStack ausgenutzt werden kann. Denken Sie an den berühmten Ping of Death. Bei diesem handelt es sich um ein ICMP-Paket, das bei einem verwundbaren Empfänger über eine manipulierte Größenangabe einen Buffer Overflow verursacht. Das Ergebnis ist ein Systemabsturz. Obwohl der Ping of Death erstmalig in den 90er Jahren bekannt geworden ist, ist selbst Solaris 10 für diesen Angriff anfällig. Anfang 2007 wurden Sicherheitslücken im Cisco-IOS bekannt, bei denen ein Angreifer über manipulierte ICMP-Pakete Code auf einen Router einschleusen kann. Der Ping of Death oder die bei Cisco bekannt gewordene Variante stellen nur dann eine ausnutzbare Sicherheitslücke dar, wenn das betroffene System per ICMP erreichbar ist. Filtert man ICMP-Pakete durch eine Firewall, besteht zwar eine theoretische Sicherheitslücke, praktisch ist sie aber nicht ausnutzbar. Das Gleiche gilt für alle anderen Protokolle. Daher sollte jegliche nicht benötigte Kommunikation durch eine Host-Firewall gefiltert werden, um Probleme wie die des Ping of Death zu vermeiden. Darüber hinaus erschwert eine Firewall die Informationssammlung über einen Server mit Hilfe eines Portscanners. Gängige Portscanner wie nmap identifizieren das jeweilige Zielbetriebssystem über eine Analyse der Antworten auf Anfragen an verschiedene Ports. Dabei spielen auch und insbesondere Antworten des Zielsystems auf Anfragen an geschlossene Ports eine große Rolle. Um dies zu verstehen, ist ein Blick auf den Aufbau einer TCP-Verbindung hilfreich. Möchte ein Host eine TCP-Verbindung zu einem anderen Host aufnehmen, sendet er ein TCP-Paket mit gesetztem SYN-Flag. Der Zielhost antwortet – sofern auf dem Zielport ein Dienst aktiv ist – mit einem TCP-Paket, bei dem die Flags SYN und ACK gesetzt sind (SYN-ACK). Der erste Host sendet dann ein TCP-Paket mit gesetztem ACK-Bit, womit die TCP-Verbindung hergestellt ist. Falls beim Zielhost auf dem im ersten TCP-Paket des Senders – das Paket mit dem gesetzten SYN-Bit – spezifizierten Zielport kein Dienst aktiv ist, antwortet der Zielhost mit einem TCP-Paket, bei dem das RST-Bit (Reset) gesetzt ist. In beiden
93
3.2
3
Systemhärtung
Fällen antwortet der Zielhost. Mit einem Portscanner können somit auch geschlossene Ports identifiziert werden. Aus dem Antwortverhalten eines Zielhosts bei offenen und geschlossenen Ports ermittelt nmap das Betriebssystem des Zielhosts. Das bedeutet, je weniger Informationen ein Zielhost preisgibt, desto weniger Informationen kann ein potentieller Angreifer über diesen Host sammeln. Die Kenntnis über das Betriebssystem eines Servers ist eine sehr wichtige Information für einen Angreifer und sollte möglichst verborgen bleiben. Daher stellt das Abschirmen nicht verwendeter Ports mit einer Host-Firewall nicht nur einen Schutz gegen versehentlich gestartete Dienste dar, sondern erschwert obendrein die Informationssammlung über ein System. Mit iptables steht unter Linux eine vollwertige Firewall zur Verfügung. iptables ist dabei genau genommen nur das Frontend, mit dem der Benutzer die Firewall konfiguriert. Die Firewall selbst wird durch das Netfilter-Modul repräsentiert. In diesem Buch verwende ich für die gesamte Firewall-Funktionalität von Linux die Bezeichnung iptables, da dies die in der Praxis gängige Bezeichnung ist. An dieser Stelle soll kein Einstieg in iptables vorgenommen werden. Aufgrund der Mächtigkeit dieser Firewall würde dieses Thema leicht ein eigenes Buch füllen. Um weitergehende Informationen zu erhalten, konsultieren Sie bitte die einschlägige Fachliteratur oder die Webseite des iptables-Projektes unter www.iptables.org. Für die Arbeit mit iptables sind die folgenden vier Begriffe wichtig: 왘
Table: Eine Table legt fest, auf welches Paket eine Regel angewendet wird. Es gibt die Standardtable FILTER für Paketfilter-Funktionalität, NAT für NATFunktionalität und MANGLE für die Manipulation von Paketen.
왘
Chain: Eine Chain ist einer der fünf Punkte PREROUTING, POSTROUTING, INPUT, OUTPUT und FORWARD. Mit den Chains wird festgelegt, an welcher Stelle eine Regel angewendet wird.
왘
Target: Ein Target gibt an, was mit einem Paket passiert. Ein Paket kann z. B. akzeptiert (ACCEPT) oder verworfen werden (DROP). Darüber hinaus stehen noch weitere Targets zur Verfügung, teilweise tablespezifisch.
왘
Pattern: Ein Pattern dient zur Formulierung von Firewall-Regeln und definiert Muster, mit denen ein Paket identifiziert wird.
Für die Absicherung eines Servers sind weder Routing, Forwarding, NAT oder Paketmanipulation notwendig, daher beschränkt sich die Arbeit mit iptables in diesem Fall auf die Tables FILTER und die Chains INPUT und OUTPUT. Standardmäßig steht iptables »auf Durchzug«, d. h., alles ist erlaubt. Eine Herangehensweise wäre, sukzessive alles, was verboten sein soll, mit einzelnen Firewall-Regeln zu verbieten. Einfacher – und sicherer – ist es aber, die beiden Chains
94
Host-Firewall
INPUT und OUPUT so zu konfigurieren, dass grundsätzlich alles verboten ist. Nur benötigte Kommunikation wird dann explizit freigeschaltet. Für die Arbeit mit iptables sind Root-Rechte notwendig, weswegen alle folgenden Befehle mit sudo ausgeführt werden. Im ersten Schritt werden alle aktiven Firewall-Regeln angezeigt: # sudo iptables -L Chain INPUT (policy ACCEPT) target prot opt source
iptables zeigt Einstellungen der Tables an (ACCEPT) und zu jeder Table die konfigurierten Regeln. Die Liste ist erwartungsgemäß klein, da noch keine Regeln konfiguriert sind. Im nächsten Schritt werden die Tables INPUT und OUTPUT so konfiguriert, dass standardmäßig jeder eingehende und ausgehende Netzwerkverkehr verworfen wird. Achtung: Falls Sie über eine Netzwerkverbindung an Ihrem Server arbeiten, klemmen Sie sich damit das Netzwerk ab! Sie sollten daher eine zweite Zugriffsmöglichkeit, z. B. über eine Administrationsoberfläche des Providers, sicherstellen. # sudo iptables -P INPUT DROP # sudo iptables -P OUTPUT DROP
Als Nächstes kann ausgehender TCP- und UDP-Verkehr grundsätzlich erlaubt werden. Es ergibt keinen Sinn, ausgehenden Netzwerkverkehr zu begrenzen. Dazu wird der Chain OUTPUT über die Muster -p tcp für TCP-Pakete und -p udp für UDP-Pakete mitgeteilt, dass diese Pakete dem Target ACCEPT zuzuleiten sind, die Pakete also ungehindert passieren dürfen. # sudo iptables -A OUTPUT -p tcp -j ACCEPT # sudo iptables -A OUTPUT -p udp -j ACCEPT
Nun können die benötigten Dienste freigegeben werden. Zunächst ist ein SSHZugang sinnvoll. Dazu werden eingehende TCP-Verbindungen auf Port 22 erlaubt: # sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT
95
3.2
3
Systemhärtung
Das Muster --dport 22 steht dabei für destination port 22. Damit eingehende TCP-Pakete, die zu bestehenden Verbindungen gehören, die Firewall passieren dürfen, wird die so genannte Stateful Inspection für diese Verbindungen aktiviert. Der Kernel führt Buch über bestehende TCP-Verbindungen, und iptables kann diesen Verbindungen die passenden TCP-Pakete zuordnen, so dass ein TCPPaket ohne gesetztes SYN-Bit, das zu keiner bestehenden Verbindung gehört, verworfen werden kann. Dazu wird zusätzlich das Muster state verwendet. # sudo iptables -A INPUT -p tcp -m state --state RELATED,ESTABLISHED -j ACCEPT
Ein Server muss DNS-Abfragen tätigen können. Die ausgehenden Abfragen sind über die obenstehende Freigabe für die OUTPUT-Chain erlaubt, eingehend fehlt aber noch eine Regel. DNS-Abfragen finden über UDP statt; UDP ist verbindungslos, weswegen eine Stateful Inspection dafür nicht existiert. Daher müssen eingehende UDP-Pakete akzeptiert werden, um die Antworten von DNS-Servern empfangen zu können. DNS-Server antworten von UDP-Port 53, weswegen die entsprechende Regel wie folgt spezifiziert werden kann: # sudo iptables -A INPUT -p udp --sport 53 -j ACCEPT
Für die Kommunikation mit Zeitservern über das NTP-Protokoll, das ebenfalls UDP verwendet, gilt dasselbe. Hier können aber die IP-Adressen der im System als zu verwendende Zeitserver konfigurierten Server direkt in die Firewall-Regel eingebaut werden. Damit sind nur NTP-Antworten von diesen Zeitservern erlaubt. NTP kommuniziert auf UDP-Port 23. # sudo iptables -A INPUT -p udp -s 130.149.17.21 --sport 123 -dport 123 -j ACCEPT # sudo iptables -A INPUT -p udp -s 131.188.3.222 --sport 123 -dport 123 -j ACCEPT
Anschließend können die vom Server bereitgestellten Dienste freigegeben werden. Für einen Webserver, der auf den Ports 80 (HTTP) und 443 (HTTPS) lauscht, müssten beispielsweise die folgenden beiden Regeln gesetzt werden: # sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT # sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT
Die Firewall-Regeln sollten natürlich beim Systemstart automatisch geladen werden. Daher sollten die Regeln in ein Skript verpackt und dieses als Init-Skript eingerichtet werden. Für Ubuntu sähe das Skript wie folgt aus:
96
Host-Firewall
#!/bin/bash # set some FW-rules # Klaus M. Rodewig # $Id: firewall,v 1.18 2008-04-27 11:00:25 kr Exp $ case "$1" in start) iptables -P INPUT DROP iptables -P OUTPUT DROP iptables -A OUTPUT -p tcp -j ACCEPT iptables -A OUTPUT -p udp -j ACCEPT # DNS iptables -A INPUT -p udp --sport 53 -j ACCEPT iptables -A INPUT -p tcp -m state --state RELATED,ESTABLISHED -j ACCEPT # NTP iptables -A INPUT -p udp -s 130.149.17.21 --sport 123 -dport 123 -j ACCEPT iptables -A INPUT -p udp -s 131.188.3.222 -# loopback iptables -A INPUT -p tcp -s 127.0.0.1 -d 127.0.0.1 -j ACCEPT ;; stop) iptables -F iptables -P INPUT ACCEPT iptables -P OUTPUT ACCEPT ;; *) echo "Usage $0 {start|stop}" ;; esac
… die beim Stoppen des Skriptes ausgeführt werden, leeren erst alle Chains und setzen dann die Standard-Policies der beiden Tables INPUT und OUTPUT auf ACCEPT. Damit wird die gesamte Firewall-Funktionalität ausgeschaltet – jeglicher Netzwerkverkehr ist ungefiltert erlaubt. Das Skript wird unter einem beliebigen Namen – naheliegend wäre »firewall« – im Verzeichnis /etc/init.d gespeichert und dem Benutzer root und der Gruppe zu-
97
3.2
3
Systemhärtung
geordnet. Die Zugriffsrechte werden auf 700 gesetzt, damit das Skript für seinen Besitzer ausführbar wird: # sudo chown root:root /etc/init.d/firewall # sudo chmod 700 /etc/init.d/firewall
Mit update-rc.d können dann – wie in Abschnitt 3.1.1 beschrieben – die notwendigen symbolischen Links für den automatischen Start angelegt werden. Die Einrichtung für Gentoo erfolgt analog zum in Abschnitt 3.1.2 gezeigten Vorgehen.
3.3
IDS-Systeme
Häufig hört oder liest man die Empfehlung, auch auf Einzelsystemen IntrusionDetection-Systeme (IDS) einzusetzen. Unter Linux wäre die erste Wahl für ein solches System Snort, ein quelloffenes und weitverbreitetes IDS. Ein IDS überwacht Netzwerkereignisse auf Anomalitäten und kann bei Abweichungen Alarme und/ oder Gegenmaßnahmen auslösen. Leider vereinigen IDS-Systeme einige grundlegende Nachteile in sich. Der erste Nachteil ist der hohe Aufwand, der für Einrichtung und Betrieb eines IDS-Systems notwendig ist. Damit ein solches System Anomalien erkennen kann, muss es erst einmal den Normalzustand kennen. Es muss also entsprechend trainiert und/oder konfiguriert werden. Wird dieser Schritt nicht ausreichend gründlich betrieben, steht die Nützlichkeit des IDS-Systems stark in Frage. Der zweite Nachteil hängt unmittelbar mit dem ersten zusammen und betrifft die Reaktion des IDS-Systems auf Anomalitäten. Hierbei verhält sich ein nicht wirklich gut konfiguriertes IDS-System in der Regel sehr digital: Entweder registriert es viele Anomalien gar nicht und stellt daher keinen Sicherheitsgewinn dar, oder es ist so sensibel konfiguriert, dass viele False Positives entstehen, Warnungen und Alarme, die gar keine sind. Das Ergebnis ist im ersten Fall, dass ein Angriff nicht erkannt wird, im zweiten Fall, dass ein Angriff vielleicht erkannt wird, der zuständige Administrator ihn aber ignoriert, da es nur eine Warnung von vielen ist. In beiden Fällen gaukelt das IDS-System eine Sicherheit vor, die es aber nicht bietet. Noch kritischer wird es, wenn ein geschickter Angreifer über ein IDS-System Reaktionen eines aufmerksamen Administrators auslösen kann. Dies wird dann zum Problem, wenn der Administrator Feierabend hat und die Reaktionen auf die Angriffe ausbleiben … Neben der grundsätzlichen Problematik beim Einsatz von IDS-Systemen gibt es beim Einsatz auf einem dedizierten Server noch ein weiteres Problem. Das IDSSystem stellt einen weiteren Dienst dar, durch den der Netzwerkverkehr laufen
98
Rechtliches
muss. Ein Fehler in diesem Dienst kann zu Fehlern auf dem ganzen System führen, eine kritische Sicherheitslücke in diesem Dienst kann bewirken, dass der gesamte Server über das IDS-System, das ihn eigentlich schützen soll, kompromittiert werden kann. Es gilt daher das in Abschnitt 3.1.6 zu diesem Thema bereits Gesagte. Darüber hinaus ist vor kurzer Zeit eine neue Angriffsklasse beschrieben worden, die Fehler in der Implementierung von Hash-Algorithmen ausnutzt. Damit lassen sich Systeme, die intern mit Hash-Algorithmen arbeiten – und zu solchen Systemen zählen auch IDS-Systeme –, durch wenige, mathematisch berechnete Pakete aus dem Tritt bringen. Das lässt den Sinn von IDS-Systemen noch fraglicher erscheinen. Ein IDS-System verschafft wenig Sicherheit, gaukelt sie aber vor und kann obendrein auch noch eine konkrete Gefahrenquelle darstellen. Von einer Verwendung sollten Sie daher absehen. Ein gründlich gehärtetes System ist die beste Verteidigung. Zwar ist nicht alles, was hinkt, ein Vergleich, aber ein IDS-System ist vergleichbar mit Überwachungskameras. Diese verhindern keine Straftat und helfen manchmal bei der Aufklärung einer solchen – eine Erkenntnis, die sich langsam auch bei Verantwortlichen durchsetzt1. Daher sollte vor dem Hintergrund endlicher Kapazitäten statt in Konfiguration und Betrieb eines IDS-Systems lieber in eine umfassende Systemhärtung investiert werden.
3.4
Rechtliches
Eine gründliche Serverhärtung dient der Sicherheit eines Systems. IT-Sicherheit sollte dabei nie als Selbstzweck verstanden werden, so wie IT selbst auch kein Selbstzweck ist. Bei professionellem Einsatz von IT wird diese in der Regel dazu verwendet, Geld zu verdienen. Dabei stellen die auf dem System verarbeiteten Informationen unmittelbare Vermögenswerte dar. Werden diese Vermögenswerte beschädigt, verändert oder gelöscht, kann das weitreichende Auswirkungen auf Geschäftsprozesse oder, im schlimmsten Fall, auf das gesamte Unternehmen haben.
3.4.1
ISO 27001
Aus diesem Grund existiert mit der ISO-Norm 27001 eine Norm zur Sicherstellung von Informationssicherheit. Entstanden aus der Norm BS7799 des British Standards stellt ISO 27001 eine weltweit anerkannte Norm dar, nach der sich Unternehmen aufstellen und von akkreditierten Prüfern zertifizieren lassen können. Durch ein solches Zertifikat wird die Einhaltung der in der ISO 27001 formulier1 http://www.heise.de/newsticker/meldung/print/107457
99
3.4
3
Systemhärtung
ten Vorgaben beschrieben. Ein wichtiges Detail ist, dass ISO 27001 keine Norm für IT-Sicherheit ist, sondern für Einführung, Umsetzung und den Betrieb eines Informationssicherheits-Managementsystems (ISMS). Das umfasst nicht nur technische Sicherheit, sondern in der Hauptsache organisatorische Prozesse und die Einbindung des Managements in das Thema Informationssicherheit. Nun hat ein ISMS für den Betreiber eines eigenen Servers in der Regel überhaupt keinen praktischen Belang, nichtsdestotrotz sind in der ISO 27001 technische Anforderungen definiert, die auch für Systembetreiber, die nicht im Rahmen eines ISMS agieren, sehr interessant sind, da sie alle wichtigen Bereiche der Informationssicherheit abdecken. Neben den Standardanforderungen von IT-Sicherheit, der Sicherstellung von Integrität, Authentizität und Vertraulichkeit von Daten, behandelt ISO 27001 auch noch die Verfügbarkeit. Alle vier Themen sind für den Betrieb eines Servers relevant, weswegen sich ein Blick auf die entsprechenden Vorgaben der Norm lohnt. ISO 27001 ist eine Unternorm der ISO-Normenreihe 27000, die verschiedene Normen zur Informationssicherheit umfasst. ISO 27002 beispielsweise, ehemals ISO 17799, bietet konkrete Umsetzungsvorschläge zu den Anforderungen der ISO 27001. Oder anders gesagt: ISO 17799 ist ein Leitfaden für konkrete Maßnahmen und Aktionen, ISO 27001 ist der Leitfaden zur Prüfung dieser Maßnahmen und Aktionen. Im letzten Kapitel dieses Buches, »Serverwartung«, finden Sie weitere Informationen zur ISO 27001 im Zusammenhang mit den rechtlichen Aspekten beim Betrieb eines eigenen Servers.
3.4.2
Dokumentation
Die Norm verlangt das Erstellen und Pflegen von Dokumentation und Verfahrensanweisungen, mit denen der Betrieb eines informationsverarbeitenden Systems sichergestellt werden kann. Dieser Punkt ist insbesondere dann von Bedeutung, wenn ein Server nicht nur als Selbstzweck betrieben wird und von verschiedenen Personen genutzt wird. Das kann der Webserver eines Vereins oder einer kleinen Firma sein, ein Spieleserver etc. In allen Fällen ist es gefährlich, wenn das Wissen über Einrichtung und Betrieb dieses Systems nur einer Person bekannt ist. Menschen können krank werden, wegziehen, sich im Streit trennen oder einfach nur vergesslich werden. Wenn dann keine Aufzeichnungen vorhanden sind, mit denen der Betrieb eines Servers sichergestellt werden kann, und seien es nur die Zugangspasswörter und -zertifikate, kann das leicht dazu führen, dass das System durch ein neues System ersetzt werden muss, mit aller Arbeit, die damit verbunden ist. Daher sollten Sie – auch wenn Sie ein System allein betreiben – alle wich-
100
Rechtliches
tigen Schritte und Verfahren dokumentieren. Gerade Tätigkeiten, die man nicht ständig ausführt, wie z. B. eine Installation, geraten schnell in Vergessenheit. Legen Sie die Dokumentation aber nicht auf einem frei zugänglichen Verzeichnis Ihres Webservers ab, einem Angreifer wäre dies sehr willkommen.
3.4.3
Änderungsverwaltung
Schon viele Systeme sind durch unbedachte Änderungen kaputtgegangen. Ein falsches Paket installiert, ein falsches Paket gelöscht, ein Fehler in einer Konfigurationsdatei, und schon bleibt das System stehen. Daher sollten Sie Änderungen an der Installation (Hinzufügen, Aktualisieren oder Löschen von Paketen) grundsätzlich protokollieren. Dabei reicht es schon, vor und nach einer Änderung die aktuelle Paketliste in eine Textdatei zu dumpen. Ubuntu: # dpkg -l > package_20080401_before.dump # [...] Änderungen am System [...] # dpkg -l > package_20080401_after.dump
Gentoo: # eix -I > package_20080401_before.dump # [...] Änderungen am System [...] # eix -I > package_20080401_after.dump
Ist dann durch die Änderungen etwas fehlgeschlagen, können Sie die Änderungen durch Vergleich der Paketlisten nachvollziehen und gegebenenfalls die alten Pakete wieder installieren. Das Gleiche gilt für die Arbeit an Konfigurationsdateien. Gewöhnen Sie sich an, vor der Änderung insbesondere systemweiter Konfigurationsdateien eine Sicherheitskopie der jeweiligen Datei anzulegen. Schlimmstenfalls kann das System mit einer Live-CD gebootet und die ursprüngliche Konfigurationsdatei so wiederhergestellt werden.
3.4.4
Protokollierung und Monitoring
Auf dem System sollten alle sicherheitsrelevanten Tätigkeiten protokolliert werden. Dies beginnt beim Logging von SSH-Verbindungen (wer hat sich wann eingeloggt?) und geht bis zum Logging von sudo-Aktivitäten. Idealerweise sollten alle relevanten Systemaktivitäten überwacht werden – mehr dazu in Kapitel 5, »Optimierung und Monitoring«. Möglicherweise ist auch der Einsatz von Tools sinnvoll, die Logfiles auf Anomalien untersuchen, wenngleich dies wieder in den Bereich IDS geht (siehe hierzu Abschnitt 3.3).
101
3.4
3
Systemhärtung
3.4.5
Detaillierte Härtungsmaßnahmen
Die Norm ISO 18028, die im Rahmen von Umstrukturierungen zur ISO 27033 wird, stellt ganz konkrete Checklisten zur Verfügung, die zur Einrichtung eines sicheren Systems abgearbeitet werden müssen (z. B. »Annex E – Checklists for Secure Web Services«). Diese decken sich mit den gängigen Vorgehensweisen (Best Practices) für die Härtung von Systemen.
102
»Für einen Reporter, der unterwegs Notizen aufschreiben will, ist das [Notebook] interessant. Aber für den Durchschnittsnutzer sind diese Geräte nicht so nützlich, und es gibt auch kaum Software dafür.« Steve Jobs
4
Serverdienste
In diesem Kapitel erfahren Sie, wie Sie Apache, Tomcat, Jabber, Datenbank-, Mail- und Datentransferdienste installieren und konfigurieren.
4.1
Apache
Die wohl verbreitetste Art von Servern im Internet sind Webserver. 15 Jahre nach der Erfindung des WWW hat dieses alle anderen Dienste im Internet an Bedeutung weit überholt und nicht zuletzt durch den Hype um das vielbesungene Web 2.0 einen weiteren Popularitätsschub erhalten. In immer stärkerem Maß werden althergebrachte Internetdienste vom WWW kannibalisiert. Viele technisch unbedarfte Benutzer kennen E-Mail nur als einen über eine Weboberfläche erreichbaren Dienst, die legendären Usenet-Groups werden immer mehr von webbasierten Foren und Diskussionsplattformen verdrängt. Eine Website ist die gängigste und einfachste Möglichkeit, im Internet Informationen für andere Benutzer zur Verfügung zu stellen. Neben dem von Tim Berners-Lee, dem Erfinder des WWW, für das CERN mit Objective-C auf NEXTSTEP entwickelten Browser und Webserver, der ersten Software für das WWW, wurde dank der Offenlegung der WWW-Spezifikationen schnell weitere Software entwickelt. Das National Center for Supercomputing an der Universität von Illinois in den USA entwickelte den NCSA-Webserver. Aus diesem entstanden in der Folgezeit verschiedene Einzelprojekte, die den ursprünglichen Softwarestamm immer weiter veränderten. Dieses Verändern der Software – Patchen – gab dem daraus entstehenden Webserver seinen neuen Namen: »a patchy server«. Daraus entstand der Name »Apache«.
103
4
Serverdienste
Geschichtsforschung Wie so häufig bei Namen ist auch der Ursprung des Namens »Apache« umstritten. Die deutschsprachige Wikipedia verneint die Entstehung aus dem Satz »a patchy server« Auch gibt die aktuelle FAQ des Apache-Projektes an, dass der Name bewusst aus Respekt vor dem gleichnamigen Indianerstamm gewählt wurde. Die ersten Versionen der Apache-FAQ hingegen erwähnen die Indianertheorie nicht, sondern geben als Ursprung den »a patchy server« an. Die Wahrheit liegt wahrscheinlich irgendwo in der Mitte. Der Apache-Webserver wird von der Apache Software Foundation entwickelt. Diese betreut neben dem Webserver noch weitere bekannte Softwareprojekte, wie z. B. den Tomcat-Server.
Die Bedeutung des Apache ist leicht an der Statistik der Firma Netcraft zu erkennen, welche die Marktanteile von Webservern im Internet überwacht. 1995 mit 10 % Marktanteil gestartet, hatte der Apache 1996 bereits alle anderen Webserver eingeholt und sich seitdem zum Marktführer entwickelt. Lange Zeit uneinholbar, änderte sich die Situation 2006, als der Apache einen großen Einbruch hinnehmen musste, da ihm vom Microsoft Internet Information Server (IIS) große Marktanteile abgenommen wurden. Experten führen diesen Einbruch des Apache und die Stärkung des IIS darauf zurück, dass mehrere große Massenhoster in den USA ihre Infrastruktur von Apache auf IIS umgestellt haben, womit eine sehr große Anzahl Domains von Apache auf IIS gewechselt hat. Netcraft misst nicht pro Server, sondern pro Domain. Die Statistik macht daher keine Angabe zur Anzahl der Installationen, sondern nur zu den Domains, die auf einem bestimmten Webserver laufen.
Abbildung 4.1
104
Webserver-Marktanteile von 1995 bis 2008
Apache
Der Apache-Webserver ist modular aufgebaut. Das bedeutet, dass gewünschte Funktionen, die nicht Bestandteil des Serverkerns sind, über Module nachgeladen werden können. Bei Modulen gibt es zwei Ausprägungen: dynamische und statische Module. Ein statisches Modul wird direkt in den Server einkompiliert. Muss das Modul erneuert werden, führt das dazu, dass der ganze Server neu kompiliert werden muss. Diesem Nachteil steht ein Performancegewinn gegenüber, denn ein statisches Modul steht direkt beim Serverstart zur Verfügung und verursacht weniger Overhead bei der Kommunikation mit dem Serverkern. Ein dynamisches Modul wird zur Laufzeit des Servers geladen. Die beliebte Skriptsprache PHP beispielsweise kann als dynamisches Apache-Modul kompiliert und in den Server geladen werden. Ein Vorteil bei dynamischen Modulen ist, dass das Neukompilieren eines Moduls kein Neukompilieren des gesamten Servers erfordert. Diese Freiheit wird mit einem kleinen Performanceverlust erkauft. Auf Servern, die keine besonderen Anforderungen erfüllen müssen, fällt dieser Verlust nicht ins Gewicht. Merkbar wird er erst beim Betrieb im Grenzbereich, d. h., wenn CPU und/oder Speicher an der Grenze ihrer Leistungsfähigkeit stehen. Falls Ihr Server nicht mit Lastproblemen zu kämpfen hat, sollten Sie daher dynamische Module vorziehen, sie erleichtern die Arbeit ungemein. Modular Beim Linux-Kernel werden statische Module übrigens auch nur dann verwendet, wenn sie unbedingt notwendig sind. So muss das Dateisystem der Startpartition beispielsweise im Kernel vorhanden sein. Müsste man für jede Versionsänderung in einem Modul, das nur zeitweise genutzt wird, den gesamten Kernel neu kompilieren, anstatt nur das betreffende Modul zu erstellen, hätte man ziemlich viel zu tun.
Den Apache gibt es in drei verschiedenen Entwicklungssträngen: 1.x, 2.0.x und 2.2.x. Der ursprüngliche Entwicklungsstrang, der für Unix-Systeme entwickelt und optimiert wurde, ist 1.x. Mit dem Entwicklungsstrang 2.x wurde eine neue Architektur eingeführt, mit der u. a. der Betrieb unter Windows verbessert wurde. Die wichtigste Neuerung hierfür war die Verwendung von Threads anstelle vom oder zusätzlich zum Forking von Prozessen wie unter Unix üblich. Darüber hinaus wurde die Modul-API verbessert. Von 2.x auf 2.2.x wurden kleinere Änderungen vorgenommen. Alle drei Entwicklungsstränge werden noch gepflegt, das Apache-Team empfiehlt aber die Verwendung des Entwicklungsstrangs 2.2.x. Der Apache 1.x arbeitet mit Forking. Dabei wird ein Vaterprozess mit Root-Rechten gestartet, die er u. a. benötigt, um den TCP-Port 80 verwenden zu können. Der Vaterprozess startet unprivilegierte Kindprozesse, die mit den Rechten des
105
4.1
4
Serverdienste
Benutzers laufen, der in der Apache-Konfiguration eingetragen ist (z. B. »www«). Die Kindprozesse beantworten die Anfragen der Clients, liefern also die Webseiten aus. Beim Forking wird vom aufrufenden Prozess über den Systemaufruf fork() eine Kopie von sich selbst erzeugt. Über das so genannte Scoreboard, einen gemeinsamen Speicherbereich, können Vater- und Kindprozesse kommunizieren. Der Vorteil beim Forking ist, dass ein Prozess autark agiert. Stürzt ein geforkter Prozess ab, hat dies keine Auswirkungen auf den Vaterprozess oder die Geschwisterprozesse. Da das Forken von Prozessen Zeit in Anspruch nimmt, erzeugt der Apache bei seinem Start schon eine in der Konfiguration definierte Anzahl von Kindprozessen, die auf eingehende Anfragen warten. Zeit ist im Internet teuer – antwortet ein Webserver nicht schnell genug, surft der ungeduldige Benutzer zur Konkurrenz. Mit der 2.x-Version des Apache wurde neben dem Forking auch Multithreading implementiert. Ein Thread ist keine Kopie eines ganzen Prozesses, sondern nur ein nebenläufiger Ausführungsstrang. Dadurch verringert sich der Ressourcenverbrauch. Obendrein kennt Windows – obwohl in frühen Versionen noch POSIX-kompatibel – kein Forking, weswegen die 1.x-Version des Apache unter Windows nicht ernsthaft zu gebrauchen war. Die Portabilität des Apache wurde durch Einführung der Apache Portable Runtime (APR) verbessert. Dabei handelt es sich um eine virtuelle Schicht, die zwischen Server und Betriebssystem liegt und die Betriebssystemaufrufe für den Server abstrahiert. Die beiden verschiedenen Arbeitsmodi des Apache – Forking und Multithreading – werden über so genannte MPMs (Multi Processing Modules) konfiguriert. Das prefork MPM verwendet Forking, das worker MPM Multithreading. Forking oder Multithreading Die Entscheidung, ob Sie Forking oder Multithreading verwenden sollen, ist relativ einfach. Wenn Sie nicht genau wissen, was der Webserver an Daten ausliefern soll, ist Forking die richtige Wahl. Forking ist stabil und bewährt. Multithreading hat unter Linux seine Berechtigung für schlanke Webserver, die unter großer Last laufen und ausschließlich statischen Inhalt ausliefern (HTML-Dateien, Grafiken, Dokumente etc.). Dabei besteht wenig Gefahr, dass ein Modul zum Absturz eines Threads führt und damit den ganzen Webserver in Mitleidenschaft zieht. Sobald dynamische Inhalte wie z. B. PHP zum Einsatz kommen, ist Multithreading keine Alternative mehr. Die Apache-Dokumentation sieht als Standardeinstellung für Unix/Linux Forking vor (prefork MPM).
106
Apache
4.1.1
Installation
Unter Ubuntu installieren Sie den Apache – wie gewohnt – mit apt-get, das zu installierende Paket heißt apache2: # sudo apt-get install apache2 Paketlisten werden gelesen... Fertig Abhängigkeitsbaum wird aufgebaut Reading state information... Fertig Die folgenden zusätzlichen Pakete werden installiert: apache2-mpm-worker apache2-utils apache2.2-common libapr1 libaprutil1 libpq5 Vorgeschlagene Pakete: apache2-doc Die folgenden NEUEN Pakete werden installiert: apache2 apache2-mpm-worker apache2-utils apache2.2-common libapr1 libaprutil1 libpq5 0 aktualisiert, 7 neu installiert, 0 zu entfernen und 3 nicht aktualisiert.
Neben dem eigentlichen Apache-Server installiert apt-get noch weitere Pakete. Dies sind u. a. das worker MPM und die APR-Bibliothek. Unter Gentoo befindet sich der Apache2 im Paket apache: # sudo emerge apache
Da der Quelltext recht umfangreich ist, dauert die Installation und das anschließende Kompilieren ein paar Minuten. In beiden Fällen, unter Ubuntu und unter Gentoo, ist zum Zeitpunkt der Manuskripterstellung die aktuelle Version 2.2.8. Ubuntu: # apache2 -v Server version: Apache/2.2.8 (Ubuntu) Server built: Feb 2 2008 03:59:12
Gentoo: # apache2 -v Server version: Apache/2.2.8 (Unix) Server built: May 18 2008 11:54:58
Warum der Apache unter Gentoo mit dem String »Unix« kompiliert wird, wo Linux gar kein Unix ist, bleibt dabei unklar.
107
4.1
4
Serverdienste
Über den Kommandozeilenparameter -v gibt der Apache seine Version aus. Eine Liste weiterer Kommandozeilenparameter erhalten Sie über -h: # apache2 -h Usage: apache2 [-D name] [-d directory] [-f file] [-C "directive"] [-c "directive"] [-k start|restart|graceful|graceful-stop|stop] [-v] [-V] [-h] [-l] [-L] [-t] [-S] [-X] Options: -D name : define a name for use in directives -d directory : specify an alternate initial ServerRoot -f file : specify an alternate ServerConfigFile -C "directive" : process directive before reading config files -c "directive" : process directive after reading config files -e level : show startup errors of level (see LogLevel) -E file : log startup errors to file -v : show version number -V : show compile settings -h : list available command line options (this page) -l : list compiled in modules -L : list available configuration directives -t -D DUMP_VHOSTS : show parsed settings (currently only vhost settings) -S : a synonym for -t -D DUMP_VHOSTS -t -D DUMP_MODULES : show all loaded modules -M : a synonym for -t -D DUMP_MODULES -t : run syntax check for config files -X : debug mode (only one worker, do not detach)
Interessant ist ein Vergleich der Compile-Optionen bei beiden Distributionen. Unter Ubuntu wurde der Apache mit den folgenden Einstellungen kompiliert: # apache2 -V Server version: Server built: Server's Module Server loaded: Compiled using: Architecture: Server MPM: threaded: forked: Server compiled [...]
Unter Gentoo: # apache2 -V Server version: Server built: Server's Module Server loaded: Compiled using: Architecture: Server MPM: threaded: forked: Server compiled [...]
Apache/2.2.8 (Unix) May 18 2008 11:54:58 Magic Number: 20051115:11 APR 1.2.11, APR-Util 1.2.10 APR 1.2.11, APR-Util 1.2.10 32-bit Prefork no yes (variable process count) with....
Die beiden Versionen unterscheiden sich in ihren Compile-Einstellungen. Gentoo verwendet das prefork MPM – erste Wahl unter Linux –, Ubuntu hingegen das worker MPM, eine Mischung aus Forking und Multithreading. Dabei erzeugt der Vaterprozess neue Prozesse, die für das Beantworten der Client-Anfragen ihrerseits Threads erzeugen. Ein Problem in einem Thread führt dann nicht zum Absturz des gesamten Servers, sondern nur des Prozesses, von dem der betreffende Thread erzeugt worden ist. Diese Betriebsart schont die Ressourcen des Systems, was durch eine potentiell erhöhte Instabilität erkauft wird. Gibt es ausreichend Systemressourcen und arbeitet der Webserver ausreichend stabil, spricht nichts gegen die Verwendung des worker MPM. Spätestens aber in Hochlastsituationen ist eine Aufteilung von dynamischen und statischen Inhalten auf entsprechend optimierte Server (prefork MPM für dynamischen Inhalt und worker MPM für statischen Inhalt) sinnvoll. Stabilität von Multithreading-Apaches Das potentielle Risiko eines Webserver-Absturzes ergibt sich beim Multithreading nicht dadurch, dass dieser Betrieb in sich instabil ist, sondern dadurch, dass ein Fehler in einem Thread auch Auswirkungen auf den Vaterprozess und alle anderen Threads haben kann, da alle Threads im selben Speicherbereich arbeiten. Externe Module, z. B. PHP, erhöhen die Komplexität des Webservers und damit auch die Gefahr von Problemen.
Nach der Installation gibt es bei beiden Distributionen ein Init-Skript, über das Sie den Apache steuern können. Da dieses aber distributionsspezifisch ist, sollten Sie lieber das zum Apache gehörende Skript apache2ctl verwenden, das sich nach der Installation im Suchpfad befindet. Die folgende Tabelle zeigt die Kommandozeilenparameter von apache2ctl:
109
4.1
4
Serverdienste
Parameter
Bedeutung
start
Startet den Apache-Dienst.
stop
Beendet den Apache-Dienst.
restart
Führt nacheinander stop und start aus.
graceful
Startet den Apache-Dienst neu, hält aber bestehende Client-Verbindungen noch so lange, bis sie beendet sind. Damit kann der Server im laufenden Betrieb von Benutzern unbemerkt neu gestartet werden.
graceful-stop
Beendet den Apache, hält aber bestehende Verbindungen noch so lange, bis sie beendet sind.
configtest
Überprüft die Konfigurationsdateien des Apache.
status
Gibt einen Status auf der Konsole aus (analog zum Handler serverstatus).
fullstatus
Gibt einen erweiterten Status auf der Konsole aus.
Tabelle 4.1 Kommandozeilenparameter von apache2ctl
Nicht zu freundlich sein Beim Neustart des Apache über graceful oder auch beim Beenden über gracefulstop gibt der Apache die Handles auf seine Logdateien so lange nicht frei, wie noch
Client-Verbindungen bestehen. Daher sollten Sie graceful und graceful-stop nie für das Rotieren von Logdateien verwenden, denn solange der Apache seine Handles nicht geschlossen hat, kann sein Skript zwar die betreffenden Logdateien verschieben oder löschen, der Speicherplatz, den diese Logdateien belegen, wird aber erst nach dem Schließen des letzten Handles freigegeben.
4.1.2
Konfiguration
Nach der Installation ist der Apache grundsätzlich einsatzbereit. Das Aufrufen der IP-Adresse des Serversystems zeigt bei Ubuntu und bei Gentoo jeweils eine Standardseite, wobei die Seite von Gentoo etwas aussagekräftiger ist und zumindest anzeigt, dass die Installation erfolgreich verlaufen ist.
Abbildung 4.2
110
Standardseite des Apache unter Ubuntu
Apache
Abbildung 4.3 Standardseite des Apache unter Gentoo
Sowohl unter Gentoo als auch unter Ubuntu befinden sich die Konfigurationsdateien des Apache im Verzeichnis /etc/apache2. Beide Distributionen verwenden unterschiedliche Dateien. Unter Gentoo ist die Datei, über die der Apache konfiguriert wird, die Datei /etc/apache2/httpd.conf, unter Ubuntu /etc/apache2/ apache2.conf. Über den Kommandozeilenparameter -f können Sie dem Apache eine alternative Konfigurationsdatei übergeben: # apache2 –f
Die Konfigurationsdatei ist – wie unter Linux üblich – eine normale Textdatei, die Direktiven zur Konfiguration des Apache enthält. Dabei steht eine Direktive pro Zeile, Zeilenumbrüche sind dabei möglich und werden durch einen Backslash gekennzeichnet. Die aktuelle Apache-Dokumentation weist 387 verschiedene Direktiven aus, was deutlich macht, dass die Konfiguration des Apache sehr umfangreich sein kann. Für den Anfang reichen in der Regel die Standardeinstellungen. Dennoch gibt es einige Direktiven, die man zumindest kennen sollte, um im Problemfall, z. B. beim Auftreten von Lastspitzen, angemessen reagieren zu können. Eine Liste aller Direktiven ist auf der entsprechenden Webseite der Apache-Group verfügbar.1 Die folgenden Abschnitte beschreiben die Konfigurationsdateien des Apache unter Ubuntu und Gentoo. Zunächst folgt ein Blick in die Konfigurationsdatei des Ubuntu-Apache. Die erste Direktive ist die folgende: ServerRoot "/etc/apache2"
Damit wird normalerweise das Verzeichnis festgelegt, in dem der Apache installiert ist. Diese ist für weitere Direktiven wichtig, die relativ zum ServerRoot arbeiten, wie z. B. die Direktive Include, mit der weitere Konfigurationsdateien eingebunden werden können. LockFile /var/lock/apache2/accept.lock
Diese Direktive legt den Speicherort der Lock-Datei des Apache fest. Dabei gibt es zwei Punkte zu beachten: Die Lock-Datei muss sich immer im lokalen Dateisystem befinden und sollte nicht in einem Verzeichnis abgelegt werden, in dem andere Benutzer schreibenden Zugriff haben und somit die Lock-Datei manipulieren können. PidFile ${APACHE_PID_FILE} PidFile ist eine Direktive, die relativ zum ServerRoot agiert. Mit PidFile kön-
nen Sie den Ort festlegen, an dem der Apache seine PID-Datei ablegt. Die PIDDatei enthält die Prozess-ID (»PID«) des Apache-Vaterprozesses. Timeout 300
Die vorstehenden Direktiven benötigt der Apache, damit er korrekt funktioniert. Timeout ist die erste Direktive in der Ubuntu-Konfiguration, die das Verhalten des Apache gegenüber den Benutzern im Netz beeinflusst. Damit lässt sich der Timeout für drei verschiedene Situationen einstellen (warum dies in einer einzigen Direktive zusammengefasst ist, fragen Sie bitte die Apache-Entwickler). Die erste Situation ist die Bearbeitung einer GET-Anfrage. Die in der Direktive Timeout festgelegte Zeit gibt an, wie lange der Apache auf die Fertigstellung einer GET-Anfrage durch einen Client wartet. Braucht dieser vom ersten Teil der Anfrage bis zur Fertigstellung länger als die in Timeout festgelegte Zeit, bricht der Apache die Verarbeitung dieser Anfrage ab. Ebenso gilt diese Direktive für POSTund PUT-Abfragen und für den Zeitraum zwischen zwei ACK-Paketen bei Antworten des Servers an den Client. KeepAlive On
In der Anfangszeit des Webs nutzten Browser und Webserver das HTTP-Protokoll in der Version 1.0. Diese Version unterstützt keine persistente Verbindung, so dass für jede neue Anfrage eine eigene TCP-Verbindung geöffnet werden muss. Dies ist nicht nur ressourcenintensiv, sondern erzeugt auch sehr viel ProtokollOverhead. Mit HTTP 1.1 wurden persistente Verbindungen eingeführt, so dass über eine bestehende TCP-Verbindung beliebig viele HTTP-Transaktionen zwischen Client und Server stattfinden können. Dies spart nicht nur Protokoll-Overhead, sondern entlastet auch verbindungsorientiert arbeitende Geräte wie Switche, Firewalls oder Loadbalancer. KeepAlives sollten Sie daher grundsätzlich aktiviert lassen und nur in begründeten Ausnahmefällen ausschalten. MaxKeepAliveRequests 100
Im Zusammenhang mit der Direktive KeepAlive ist die Direktive MaxKeepAliveRequests wichtig. Diese legt fest, wie viele Anfragen über eine bestehende Verbindung erlaubt sind. Ein zu geringer Wert kann die Effizienz von KeepAlives
112
Apache
stark negativ beeinträchtigen. Eine allgemeingültige Aussage über einen Idealwert gibt es nicht, dieser ist insbesondere von Art und Struktur der vom Webserver ausgelieferten Daten abhängig. Liefert der Webserver hauptsächlich viele kleine Dateien aus, z. B. kleine Webseiten mit vielen Bildern, ist ein hoher Wert sinnvoll. KeepAliveTimeout 15
Ebenfalls wichtig im Zusammenhang mit KeepAlives ist die Direktive KeepAliveTimeout. Diese legt die Zeit fest, nach der eine bestehende Verbindung vom Apache abgebaut wird, wenn keine Anfragen mehr durch diese Verbindung laufen. Dieser Wert ist von großer Bedeutung für das Tuning des Webservers, denn wenn dieser Wert zu groß ist, hält der Server inaktive Verbindungen unnötig lange offen, belegt damit also entsprechend Ressourcen. Ist dieser Wert zu klein, werden aktive Verbindungen zu früh geschlossen, was die Effizienz von KeepAlives mindert. Ein Idealwert ist daher wieder stark individuell. Auf einer Webseite, bei der Benutzer weniger Anfragen tätigen und lange ohne Aktionen verweilen, können Sie den Wert größer wählen. Bei Webseiten, die aufgrund ihrer Struktur viele Anfragen pro Verbindung provozieren, können Sie den Wert entsprechend kleiner wählen. In Abschnitt 4.1.7 erfahren Sie mehr zu diesem Thema. Die nächste Direktive IfModule prüft auf das Vorhandensein des Moduls mpm_ prefork. Ist das Modul vorhanden, werden die zwischen IfModule und /IfModule stehenden weiteren Direktiven ausgewertet. Dies ist nützlich, um modulspezifische Direktiven nur dann auszuwerten, wenn das betreffende Modul auch wirklich vorhanden ist. Im vorliegenden Fall beziehen sich die Direktiven daher auf das prefork-Modul. StartServers 5 MinSpareServers 5 MaxSpareServers 10 MaxClients 1024 MaxRequestsPerChild 0
Die Direktive StartServers legt fest, wie viele Kindprozesse der Vaterprozess beim Start erzeugt. Diese Direktive ist für das Tuning des Apache nicht besonders hilfreich, denn beim Serverstart ist das Antwortverhalten des Webservers recht unerheblich. Interessanter ist die Direktive MinSpareServers. Damit können Sie festlegen, wie viele untätige Kindprozesse der Apache mindestens für neue Anfragen vorhalten soll. Der Sinn ist klar: Erhält der Webserver eine neue Anfrage, kann er aus dem Pool der untätigen Kindprozesse direkt einen zur Bearbeitung der Anfrage verwenden. Der Benutzer erhält also schnellstmöglich eine Antwort.
113
4.1
4
Serverdienste
Muss der Server aber erst einen Prozess starten, ist das Antwortverhalten wesentlich schlechter. Die Anzahl der untätigen Prozesse darf nicht beliebig hochgesetzt werden, da jeder Prozess natürlich Speicher verbraucht. Sind weniger als mit MinSpareServers definierte Prozesse vorhanden, erzeugt der Vaterprozess neue Prozesse, und zwar einen Prozess nach einer Sekunde, nach einer weiteren Sekunde zwei Prozesse, nach einer weiteren Sekunde vier Prozesse usw. Bis zur Version 1.3 hat der Apache immer nur einen Prozess pro Sekunde erzeugt, was bei stark belasteten Servern dazu geführt hat, dass das Erzeugen der gewünschten Anzahl von Prozessen unnötig lange gedauert hat. Analog zu MinSpareServers legt MaxSpareServers die maximale Anzahl von untätigen Kindprozessen fest. Prozesse, die keine Anfragen mehr beantworten, werden vom Vaterprozess beendet. Die Direktive MaxClients ist wohl die Direktive mit den größten Auswirkungen auf den Server, insbesondere bei hoher Last. MaxClients definiert die maximale Anzahl von Anfragen, die der Server beantworten kann. Ist dieser Wert zu niedrig, wird der Server weniger Anfragen beantworten, als er eigentlich kann, ist der Wert zu hoch, wird die durch die hohe Anzahl an Anfragen verursachte Last (CPULast, Speicherverbrauch, I/O) dazu führen, dass der Server »in die Knie« geht. Dabei setzt sich häufig eine Kettenreaktion in Gang. Wenn z. B. MaxClients zu hoch gewählt ist und die vom Apache erzeugten Prozesse den gesamten physischen Speicher belegt haben, wird das Betriebssystem anfangen, den virtuellen Speicher zu verwenden – es fängt an zu swappen. Für den Besucher einer Webseite äußert sich das in katastrophalen Antwortzeiten des Servers. Die erste Reaktion eines Besuchers ist in solchen Fällen, die Seite erneut anzufordern, also hektisch den Reload-Knopf des Browsers zu drücken. Dies führt aber nur zu noch mehr Last, der Server wird noch langsamer. Häufig ist dann die einzige Rettung für den Serverbetreiber das Abschalten des Apache, damit die bestehenden Verbindungen unterbrochen werden. Anschließend kann der Wert von MaxClient angepasst und der Apache wieder hochgefahren werden. Mehr dazu in Abschnitt 4.1.7. Die letzte Direktive zum prefork-Modul in der Apache-Konfiguration ist MaxRequestsPerChild. Damit können Sie festlegen, wie viele Anfragen ein Kindprozess während seiner Existenz bearbeitet. Übersteigt die Anzahl der Anfragen den definierten Wert, beendet der Vaterprozess den betreffenden Kindprozess. Das dadurch erreichte automatische Beenden von Prozessen ist insbesondere bei Webservern, die dynamische Inhalte über Module wie PHP ausliefern, sinnvoll, da sich auf diese Weise Probleme durch unentdeckte Speicher- oder andere Ressourcenlecks vermeiden lassen. Bevor ein Prozess durch einen Fehler unnötig viele Ressourcen verbraucht, wird er automatisch beendet.
114
Apache
Automatische Systembereinigung Es ist daher keine gute Idee, den Wert auf null zu setzen, da ein Kindprozess dann nicht automatisch beendet werden kann. Sie sollten den Standardwert unter Ubuntu daher entsprechend ändern.
Der nächste Block dient zur Konfiguration des worker-Moduls. StartServers 2 MaxClients 150 MinSpareThreads 25 MaxSpareThreads 75 ThreadsPerChild 25 MaxRequestsPerChild 0
Die einzelnen Direktiven innerhalb dieses IfModule-Bereiches entsprechen in ihrem Sinn den Direktiven für das prefork-Modul. StartServers legt die Anzahl der zu startenden Server fest, MaxClients gibt die maximale Anzahl von Threads an, die der Apache für die Bearbeitung von Client-Anfragen erzeugen darf. MinSpareThreads legt fest, wie viele untätige Threads mindestens verfügbar sein
sollen, MaxSpareThreads bestimmt das Gegenteil, die maximale Anzahl unbeschäftigter Threads. Unbeschäftigte Threads werden so lange vom Vaterprozess beendet, bis die Anzahl geringer als MaxSpareThreads ist. ThreadsPerChild gibt an, wie viele Threads ein Kindprozess erzeugen darf. Die Direktive MaxRequestsPerChild haben Sie weiter oben bereits kennengelernt, sie legt die Anzahl von Anfragen fest, die ein Kindprozess beantworten darf, bevor er vom Vaterprozess beendet wird.
Vor noch gar nicht so langer Zeit konnte ein Standard-Apache lediglich 256 MaxClients verkraften. Der Grund dafür lag in der festen Codierung dieses Wertes im Quelltext. Wollte man einen Apache haben, der mehr als 256 Clients parallel bedienen konnte, musste man den Parameter ServerLimit ändern bzw. den Apache mit dem entsprechenden Configure-Parameter übersetzen. Da moderne Hardware locker mehr als 256 Prozesse verkraften kann, ist es mehr als bequem, dass diese Einschränkung nicht mehr existiert. An die Stelle des hartkodierten Wertes ist die Direktive ServerLimit getreten. Mit dieser Direktive können Sie die Obergrenze für die Direktiven MaxClients und ThreadLimit (beim worker MPM) festlegen. Die Apache-Entwickler haben den maximalen Wert von ServerLimit im Quelltext auf 20.000 gesetzt, was für die nächsten Jahre mehr als ausreichend sein sollte.
115
4.1
4
Serverdienste
Denken Sie beim Anpassen von MaxClients und/oder ThreadLimit daher immer daran, nicht über den durch ServerLimit festgesetzten Wert zu gehen. Sicherheitshalber weist der Apache beim Prüfen der Konfigurationsdatei aber auch darauf hin. Wichtig ist ebenfalls, dass Sie ServerLimit auf einen sinnvollen Wert setzen, denn es reserviert abhängig vom eingestellten Wert shared Memory – je größer ServerLimit, desto mehr shared Memory wird reserviert. Das bedeutet, dass ein zu hoher Wert von ServerLimit zu viel ungenutzten Speicher belegt. Mehr dazu enthält Abschnitt 4.1.8 beim Thema Tuning. Die nächsten beiden Direktiven haben unmittelbaren Einfluss auf die Sicherheit des Systems: User ${APACHE_RUN_USER} Group ${APACHE_RUN_GROUP}
Die Direktive User legt das Benutzerkonto fest, unter dem die Apache-Prozesse laufen, die Direktive Group das entsprechende Gruppenkonto. Entgegen einem weitverbreiteten Irrtum muss und sollte der Apache niemals mit Root-Rechten laufen! Der Vaterprozess läuft zwar automatisch mit Root-Rechten, damit er sich an den privilegierten TCP-Port 80 binden kann, die Kindprozesse laufen aber ausschließlich in dem durch die beiden vorstehenden Direktiven definierten Benutzerkontext. Dabei sollte dieser Benutzerkontext so wenige Rechte wie möglich aufweisen. Der Grund liegt auf der Hand: Kann ein Angreifer eine Webseite kompromittieren und beispielsweise über eine fehlerhaft programmierte PHP-Seite auf dem Webserver auf Dateien oder Funktionen des Betriebssystems zugreifen, laufen diese Aktionen mit den Rechten des Webservers. Ein Webserver, der mit Root-Rechten läuft, bietet in einem solchen Fall den kompletten Zugriff auf alle Ressourcen des Systems, z. B. auf die Datei /etc/shadow, in der sich die PasswortHashes der Systembenutzer befinden. Die nächste Direktive legt das Format der so genannten dezentralen Konfigurationsdateien fest. Mit Hilfe dieser Dateien können Sie verzeichnisspezifische Konfigurationen erstellen. Damit ist es möglich, Konfigurationsdirektiven auf bestimmte Verzeichnisse zu beschränken, in denen diese Dateien abgelegt werden. Darüber hinaus lässt sich mit diesen Dateien auch ein simpler Passwortschutz für Verzeichnisse realisieren. Standardmäßig haben diese Dateien den Namen .htaccess. AccessFileName .htaccess
Fluch oder Segen: .htaccess Verteilte Konfigurationsdateien bieten einen Vorteil, wenn auf einem Webserver die Webpräsenzen verschiedener Benutzer liegen wie z. B. bei kommerziellen Webhostern.
116
Apache
Mit Hilfe von .htaccess-Dateien können die einzelnen Benutzer für ihre Webpräsenzen individuelle Direktiven verwenden. Demgegenüber stehen zwei große Nachteile dieser Konfigurationsart. Der erste Nachteil ist: Der Serveradministrator verliert sehr schnell den Überblick über die Konfiguration des Webservers. Zwar lässt sich festlegen, welche Art von Direktiven in den verteilten Konfigurationsdateien auftauchen dürfen, die Aufteilung der Konfiguration an viele verschiedene Stellen bleibt trotzdem unübersichtlich. Der zweite Nachteil ist, dass der Apache bei erlaubter Verwendung von .htaccess-Dateien bei jedem Request zunächst das Vorhandensein einer .htaccess-Datei im betreffenden Verzeichnis prüft. Das bedeutet, dass für jeden Request ein Dateizugriff für eine .htaccess-Datei durchgeführt wird. Bei Hochlastsystemen kann dies zu einer merklichen Beeinträchtigung der Performance führen.
.htaccess-Dateien enthalten mitunter sensible Daten. Da der Apache standardmäßig alle Dateien ausspielt, die sich in seinem DocumentRoot befinden, können auch .htaccess-Dateien mit einem Browser abgerufen werden. Kritisch wird dies insbesondere, wenn Sie .htaccess-Dateien zur Realisierung eines Zugriffschutzes verwenden. In diesem Fall enthalten die betreffenden .htaccess-Dateien die Namen der Benutzer, die für den entsprechenden Bereich autorisiert sind. Darüber hinaus sind darin auch die Dateien zu finden, in denen die Passwörter dieser Benutzer abgelegt sind. In der Regel heißen diese Dateien – analog zu den .htaccess-Dateien – .htpasswd. Zugriffsschutz mit .htaccess Um ein Verzeichnis mit einer .htaccess-Datei zu schützen, muss eine Datei dieses Namens im betreffenden Verzeichnis liegen und den folgenden Inhalt haben: AuthType Basic AuthName “Geheim“ AuthUserFile /etc/apache2/.htpasswd require valid-user
Damit definieren Sie einen Bereich mit dem Namen »Geheim«, auf den nur Benutzer Zugriff erhalten, die in der Datei /etc/apache2/.htpasswd aufgeführt sind. Der Inhalt einer .htpasswd-Datei wird mit dem Tool htpasswd aus der Apache-Distribution erstellt. Eine neue Datei mit einem neuen Benutzer kr legen Sie wie folgt an (sudo brauchen Sie nur, um die Datei im Verzeichnis /etc/apache2 ablegen zu können): sudo htpasswd -c /etc/apache2/.htpasswd kr
Anschließend steht der Benutzer kr samt seines Passwort-Hashes in der angegebenen Datei: # cat .htpasswd kr:4nsjs9NXhyn6Y
Wichtig ist, dass die Passwort-Dateien nicht im DocumentRoot abgelegt werden, um versehentliches Ausspielen durch den Server zu verhindern.
117
4.1
4
Serverdienste
Der folgende Abschnitt zeigt zwar, wie Sie dem Apache das Ausspielen dieser Dateien über eine entsprechende Konfigurationsanweisung abgewöhnen können, allerdings können Fehlkonfigurationen solche Direktiven unwirksam machen – und in einem solchen Fall ist es sehr hilfreich, wenn der Apache die entsprechenden Dateien gar nicht ausliefern kann.
Es ist sinnvoll, dem Apache das Ausspielen von Dateien, die mit ».ht« beginnen, zu verbieten. Dazu können Sie die Direktive Files verwenden, die als Parameter ein Suchmuster (regulärer Ausdruck) akzeptiert, das die zu behandelnden Dateien spezifiziert, und die verschiedene Direktiven einschließt, die für die durch das Suchmuster spezifizierten Dateien gelten sollen. Order allow,deny Deny from all
In diesem Fall wird das Ausspielen aller Dateien, die mit ».ht« beginnen, verboten. Dazu legt der reguläre Ausdruck "^\.ht" zunächst die Dateien fest, für welche die folgenden Direktiven gelten sollen. Die Direktive Order legt die Reihenfolge fest, in der die folgenden allow/deny-Direktiven ausgewertet werden. Order wird bei jedem Request, d. h. bei jedem Abruf einer Webseite, abgearbeitet. Die Reihenfolge der Schlüsselwörter allow und deny gibt an, welche Art von Direktive zuerst vorhanden sein muss, damit der aktuelle Request erlaubt bzw. verboten wird. In der vorliegenden Form (allow, deny), führt der erste Treffer einer allow-Direktive dazu, dass der Apache den aktuellen Request beantwortet. Findet der Apache keine passende allow-Direktive, weist er den Request ab, der Benutzer erhält ab Browser eine entsprechende Fehlermeldung (HTTP 403 – Forbidden). Im vorliegenden Fall existiert keine allow-Direktive, woraus folgt, dass der Apache sämtliche Zugriffe auf .ht-Dateien verbietet. Die Direktive … Deny from all
… stellt ein zusätzliches Sicherheitsnetz dar, denn diese Direktive verbietet Zugriffe auf die mit Files spezifizierten Dateien von überall. all steht dabei für alle möglichen Hosts und alle möglichen Netzwerke. Mögliche Ziele definieren Mit den Direktiven allow from und deny from können Sie den Zugriff auf Dateien für einzelne Hosts, Domains, Subdomains oder ganze Netzwerke gezielt steuern. Allow from 127. erlaubt beispielsweise den Zugriff über das lokale Loopback-Interface.
118
Apache
Deny from 127. hingegen verbieten den Zugriff darüber. Netzwerke können Sie durch
die Netzwerkadresse und die dazugehörige Bitmaske festlegen: Allow from 192.168.100.0/24 Deny from 10.10.0.0/255.255.0.0
Möglich sind auch kanonische Namen: Allow from: mgmt.foo.bar Deny from: foo.bar
Ein Webserver liefert in der Regel eine Vielzahl von Dateitypen aus. HTML-Dateien, Grafiken, PDF-Dateien, dynamische Inhalte wie PHP oder JavaServer Pages etc. Normalerweise gibt der Webserver dem Client bei der Auslieferung einer Datei an, um welchen MIME-Typen es sich bei der Datei handelt. Die Direktive … DefaultType text/plain
… legt den Standardtyp fest, den der Apache zu einem Client meldet, wenn er den MIME-Type nicht korrekt erkennen kann bzw. wenn für den Typ keine entsprechende Zuordnung existiert. Bei Ubuntu meldet der Apache für alle unbekannten Dateien den Typ text/plain. Ob das sinnvoll ist, sei dahingestellt. Diese Direktive sollten Sie dem Zweck Ihres Webservers anpassen. In seltenen Fällen kann es notwendig sein, dass der Apache die IP-Adressen der anfragenden Clients über DNS-Lookups in kanonische Namen übersetzt. Diese Namen schreibt der Apache dann in seine Logdatei oder legt sie zur weiteren Verarbeitung in der Umgebungsvariable REMOTE_HOST ab. Über die Direktive HostnameLookups können Sie dieses aktivieren. Standardmäßig steht die Direktive allerdings auf off: HostnameLookups Off
Performancebremse DNS-Lookups Das Nachschlagen von DNS-Namen dauert seine Zeit. Muss der Apache für jeden eingehenden Request einen DNS-Lookup durchführen, macht sich das auch schon bei wenig frequentierten Webpräsenzen durch verlängerte Antwortzeiten stark bemerkbar. Sofern Sie die DNS-Namen der zugreifenden Clients nicht aus Gründen der Applikationssicherheit benötigen, sollten Sie den Apache keine DNS-Lookups durchführen lassen. Falls Sie DNS-Einträge in den Logdateien des Apache benötigen, um die Lesbarkeit zu erhöhen, können Sie die Logdateien mit dem Tool logresolve auch offline so umwandeln, dass statt IP-Adressen DNS-Namen in den Dateien stehen. logresolve ist Bestandteil der Apache-Distribution.
2 http://www.webalizer.com/
119
4.1
4
Serverdienste
Auswertungstools wie z. B. Webalizer2 führen beim Parsen der Logfiles allerdings bereits selbständig DNS-Lookups für alle IP-Adressen durch, so dass ein separates Bearbeiten der Logdateien mit logresolve häufig nicht notwendig ist. Damit Sie .htaccess-Dateien für den Zugriffsschutz verwenden können, muss in der zentralen Konfigurationsdatei des Apache die Direktive … AllowOverride AuthConfig
… gesetzt sein.
Die nächsten beiden Direktiven legen die Logdatei fest, in die der Apache seine Fehlermeldungen schreibt, und die »Geschwätzigkeit«, mit der er es tut. Diese entspricht den Logleveln des Syslog-Daemons (emerg, alert, crit, error, warn, notice, info und debug): ErrorLog /var/log/apache2/error.log LogLevel warn warn ist ein guter Kompromiss, denn debug schreibt so ausführliche Logdateien,
dass die Analyse schwierig wird, emerg hingegen schreibt nur im schlimmsten Fall einen Eintrag in die Logdatei. Falls Sie mit Problemen zu kämpfen haben, kann ein kurzfristiges Aktivieren des Loglevels debug bei der Problemlösung helfen, für produktive Systeme sollte der Loglevel aber herabgesetzt werden, da zu ausführliches Logging die Systemperformance negativ beeinflussen kann. Das Format der ErrorLog-Datei lässt sich nicht ändern, wohl aber das der AccessLog-Datei, in die der Apache die Zugriffe durch die Clients loggt. Das Format der AccessLog-Datei ist frei konfigurierbar. Dazu dient die Direktive LogFormat: LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{UserAgent}i\"" combined LogFormat "%h %l %u %t \"%r\" %>s %b" common LogFormat "%{Referer}i -> %U" referer LogFormat "%{User-agent}i" agent
Name und Pfad der AccessLog-Datei sind unter Ubuntu nicht in der zentralen Konfigurationsdatei gespeichert, sondern in einer der über die folgenden Include-Direktiven definierten weiteren Konfigurationsdateien: Include Include Include Include Include Include
In den Anfangszeiten des Apache war die Konfiguration über verschiedene Konfigurationsdateien verteilt. Später wurden der Übersichtlichkeit halber diese Dateien zur zentralen httpd.conf zusammengefasst. In jüngerer Zeit gehen die Linux-
120
Apache
Distributoren jedoch wieder dazu über, die Konfiguration auf verschiedene Dateien aufzuteilen, was die Übersichtlichkeit nicht gerade fördert. In der Praxis wird man – vor allen Dingen beim Einsatz virtueller Hosts – die Konfiguration ohnehin auf verschiedene Dateien aufteilen, z. B. für jeden virtuellen Host eine eigene Datei. Die vom jeweiligen Distributor vorgenommene Aufteilung hingegen erschwert das Prüfen der Standardkonfiguration, die im Fall von Ubuntu für einen Produktivbetrieb leider nur eingeschränkt empfehlenswert ist. Die letzten beiden Direktiven der Ubuntu-Konfiguration sollten Sie umgehend ändern: ServerTokens Full ServerSignature On
Die erste, ServerTokens, definiert die Angaben, die der Apache im Server-Feld des HTTP-Headers in seinen Antworten macht. Dabei gilt aus Sicherheitsgründen: Je weniger Angaben gemacht werden, desto besser. Leider ist die Ubuntu-Standardeinstellung full die unsicherste, da sie nicht neben dem String »Apache«, den der Apache immer sendet, auch die Versionsnummer des Webservers, die aktivierten zusätzlichen Module und das Betriebssystem angibt: # GET -sed http://hardy/ 200 OK Connection: close Date: Sun, 15 Jun 2008 17:55:25 GMT Server: Apache/2.2.8 (Ubuntu)
Allein schon das Wissen um Version und Plattform ist eine wertvolle Information für einen Angreifer, da dieser gezielt nach Sicherheitslücken für diese Version suchen kann. Wenn Sie sehen wollen, wie weit man mit diesen Informationen kommt, geben Sie bei Google als Suchbegriffe »apache 1.3 linux vulnerable« ein … Noch kritischer wird es bei installierten Zusatzmodulen. Ist PHP installiert, gibt der Apache im Header den folgenden Server-String aus: # GET -sed http://hardy/ 200 OK Connection: close Date: Sun, 15 Jun 2008 18:00:25 GMT Server: Apache/2.2.8 (Ubuntu) PHP/5.2.4-2ubuntu5.1 with SuhosinPatch
Einfacher kann man die Informationsgewinnung für einen Angreifer wirklich nicht machen. Daher sollten Sie die Direktive ServerTokens umgehend auf den am wenigsten »geschwätzigen« Wert bringen: ServerTokens Prod
121
4.1
4
Serverdienste
Damit gibt der Apache lediglich noch den String »Apache« aus. Dies können Sie nur noch verhindern, indem Sie den Quellcode ändern und den Apache neu kompilieren. Allerdings wäre dies schon ein wenig sehr paranoid, belassen Sie es einfach bei der vorstehenden Einstellung. Das Ergebnis ist beruhigend: # GET -sed http://hardy/ 200 OK Connection: close Date: Sun, 15 Jun 2008 18:01:50 GMT Server: Apache
Open Source und die Versionsnummern Insbesondere beim Einsatz von Open-Source-Produkten stellt eine öffentliche Preisgabe der eingesetzten Versionsnummer eine potentielle Gefahr dar. Kennt ein Angreifer die Version einer bei seinem Opfer eingesetzten Software, kann er sich ohne weiteres den Quelltext dieser Software besorgen und gezielt nach Sicherheitslücken suchen. Daher sollten die Versionsnummern eingesetzter Open-Source-Software grundsätzlich verborgen bleiben. Nein, dies ist keine Aussage gegen die Verwendung von Open Source – nur ein Ratschlag, damit diese Verwendung nicht zum Risiko wird.
Parallel zur Angabe im HTTP-Header gibt der Apache auf Standardseiten wie Fehlermeldungen oder Verzeichnislistings im Footer auch Informationen über sich selbst aus, abhängig von der durch die Direktive ServerSignature festgelegten Einstellung: ServerSignature On
Abbildung 4.4 ServerSignature On
122
Apache
Diese Direktive sollten Sie daher analog zu ServerTokens umgehend nach der Installation anpassen: ServerSignature Off
Bei Gentoo sind die beiden Direktiven ServerTokens und ServerSignature übrigens korrekt gesetzt: Secure by Default. Damit der Apache korrekt funktionieren kann, fehlen noch einige Direktiven. Diese sind bei Ubuntu nicht in der zentralen Konfigurationsdatei gespeichert, sondern in den per Include eingebundenen weiteren Konfigurationsdateien. Die wichtigste der fehlenden Direktiven ist die Listen-Direktive. Darüber teilen Sie dem Apache mit, an welche IP-Adresse und an welchen Port – an welchen Socket – er sich binden soll, um auf eingehende Anfragen zu warten. Unter Ubuntu ist diese Direktive in der Datei ports.conf definiert (eingebunden über Include /etc/apache2/ports.conf): Listen 80 Listen 443
In diesem Fall bindet sich der Apache an Port 80 auf allen verfügbaren IP-Adressen. An Port 443 bindet er sich nur, wenn das Modul mod_ssl geladen ist, der Apache also als HTTPS-Webserver läuft. Wenn Sie mehrere IP-Adressen auf Ihrem Server haben und der Apache sich nur an eine bestimmte Adresse binden soll, kann die Listen-Direktive entsprechend geändert werden: Listen 10.10.10.1:80
In diesem Fall bindet sich der Apache nur an die IP-Adresse 10.10.10.1. Virtuelle Hosts Ein von Einsteigern gerne gemachter Fehler ist der Versuch, über die Listen-Direktive virtuelle Hosts zu erzeugen. Dies kann nicht funktionieren, da die Listen-Direktive dem Apache zwar mitteilt, an welche Sockets er sich binden soll, nicht aber, was er mit Anfragen an bestimmte Sockets tun soll. Dafür ist eine eigene Konfiguration über die VirtualHost-Direktive notwendig. Wie das funktioniert, sehen Sie im nächsten Abschnitt.
Virtuelle Hosts Mitunter kommt es vor, dass mehr als eine Website auf einem Webserver laufen soll. Dazu können Sie für jede Website oder Domain eine eigene IP-Adresse vergeben, was aber nicht erst seit der zunehmenden Knappheit von IPv4-Adressen
123
4.1
4
Serverdienste
schwierig ist (welcher Provider rückt gerne IP-Adressen raus?). Der elegantere und empfohlene Weg ist das Verwenden von namensbasierten virtuellen Hosts. Bis zur Einführung von HTTP 1.0 konnte ein Client, also die Browsersoftware, in der Anfrage an einen Webserver nur die IP-Adresse des Servers und die gewünschte Datei spezifizieren. Um mehrere Websites oder Domains auf einem Server zu betreiben, blieb dabei nur die obengenannte Möglichkeit, für jede Webpräsenz eine eigene IP-Adresse zu verwenden. Mit HTTP 1.1 ist das Protokoll um ein kleines, aber wichtiges Detail erweitert worden, das Host-Feld im Header. In dieses Host-Feld trägt der Client den Namen des Hosts ein, den er kontaktieren möchte. Der Apache kann anhand dieses Namens die Anfrage dem korrekten virtuellen Host zuordnen, ohne dass dafür eine zusätzliche IP-Adresse notwendig ist. Im folgenden Beispiel ist der vom Client angefragte Host das System www der Domain galileo-press.de: GET http://www.galileo-press.de:80/ HTTP/1.1 Host: www.galileo-press.de User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/ 20031007 Firebird/0.7 Accept: image/png,*/*;q=0.5 Accept-Language: de-de,de;q=0.8,en-us;q=0.5,en;q=0.3 Accept-Encoding: gzip,deflate Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Keep-Alive: 300 Proxy-Connection: keep-alive
Auf derselben IP-Adresse wie www.galileo-press.de können noch beliebig viele weitere Domains und Webpräsenzen betrieben werden. Solange der Client einen gültigen Host-Eintrag im HTTP-Header mitschickt – was alle modernen Webbrowser machen –, kann der Webserver die Anfragen ohne Verwendung zusätzlicher IP-Adressen an die richtigen virtuellen Server verteilen. Für die Verwendung namensbasierter virtueller Hosts benötigen Sie zwei Direktiven. Die erste ist die Direktive NameVirtualHost, mit der Sie dem Apache sagen, an welchen Socket er den virtuellen Host binden soll. Denken Sie dabei an die Warnung von oben. Listen Der Apache bindet sich nur an Sockets, die mit der Listen-Direktive festgelegt sind. Wenn Sie bei NameVirtualHost einen Socket, der kein Pendant in einer Listen-Direktive hat, angeben, wird der virtuelle Host nicht funktionieren.
Anschließend müssen Sie in dem Pärchen alle Einstellungen kapseln, die für den betreffenden Host gelten sollen. Ein Beispiel
124
Apache
gibt die Standardkonfiguration von Ubuntu. Hier ist der Hauptserver in einen virtuellen Server verlagert. Zu finden ist dies in der Datei /etc/apache2/sites-enabled/ 000-default. In dieser Datei ist die gesamte Detailkonfiguration des Standardservers abgelegt, weswegen an dieser Stelle die Direktiven im Einzelnen erläutert werden. Die erste Direktive legt den Socket fest, an den der Apache den virtuellen Host bindet. Das Sternchen steht dabei für alle im System verfügbaren IP-Adressen, d. h., der virtuelle Server ist auf allen IP-Adressen erreichbar. NameVirtualHost *
Die Direktive VirtualHost eröffnet die Konfiguration für diesen virtuellen Host und umfasst die gesamte Datei, was bedeutet, dass sich alle in dieser Datei vorgenommenen Einstellungen nur auf diesen virtuellen Host beziehen. Reichweite von Direktiven Die außerhalb der VirtualHost-Direktive stehenden Direktiven gelten für den gesamten Server, d. h. auch für alle virtuellen Hosts. Innerhalb der VirtualHost-Direktive stehende Direktiven gelten nur für den betreffenden virtuellen Host. Wichtig ist, dass bei der Verwendung von virtuellen Hosts der Hauptserver auch in einen virtuellen Host ausgelagert werden muss – so wie es auch bei Ubuntu der Fall ist. Direktivenabschnitte wie Files oder Directory können Sie beliebig schachteln. Aber beherzigen Sie dabei die alte Programmiererregel, dass zu tiefe Verschachtelungen nur zu einem führen, zur Verwirrung desjenigen, der die Konfiguration verstehen muss. Häufig lässt sich eine Konfiguration auch wesentlich eleganter schreiben, als x-fache Verschachtelungen zu konstruieren.
Diese Direktive gilt für den Hauptserver und stellt den Anfang der Konfiguration für den virtuellen Host da. Bis zur abschließenden Direktive gelten alle folgenden Direktiven für diesen virtuellen Host. ServerAdmin webmaster@localhost
Bei manchen Fehlermeldungen gibt der Apache einen Kontakt an, den ServerAdmin. Mit dieser Direktive können Sie die E-Mail-Adresse des Serververantwortlichen für diesen Zweck festlegen. Eine der wichtigsten Direktiven ist die zur Festlegung des so genannten DocumentRoots. Dahinter verbirgt sich das Verzeichnis, in dem der Apache die auszuliefernden Webseiten findet. Das Verzeichnis muss daher für den Apache-Prozess lesbar sein (idealerweise gehört es dem Apache-User). Beachten Sie, dass alle Dateien und Verzeichnisse innerhalb und unterhalb des DocumentRoots vom Apa-
125
4.1
4
Serverdienste
che ausgeliefert werden – sofern Sie ihn nicht durch entsprechende Direktiven daran hindern. Die Direktive zur Festlegung des DocumentRoots heißt ebenso: DocumentRoot /var/www/
Das DocumentRoot können Sie als absoluten Pfad angeben – mit führendem Slash – oder als Pfad relativ zum ServerRoot. Im letzteren Fall entfällt der führende Slash. Oh, Ubuntu! Die Apache-Dokumentation empfiehlt, das DocumentRoot ohne abschließenden Slash anzugeben. Bei Ubuntu ist dies standardmäßig nicht der Fall (/var/www/). Das stellt kein direktes Problem dar, lässt nur zusammen mit Details wie ServerTokens und ServerSignature einen gewissen Interpretationsspielraum bezüglich der Gründlichkeit, mit der die Ubuntu-Maintainer das Apache-Paket geschnürt haben. Interessant ist auch, dass in der Apache-Konfiguration unter Ubuntu die Direktive ServerName, die dem Apache seinen eigenen Namen mitteilt, fehlt. Das führt beim Start des Apache zu der folgenden Fehlermeldung: apache2: Could not reliably determine the server's fully qualified domain name, using 127.0.1.1 for ServerName
Nur nebenbei bemerkt: Bei Gentoo ist das DocumentRoot korrekt gesetzt – auch existiert die Direktive ServerName.
Die nächste Direktive dient wieder der Gruppierung von Direktiven für einen bestimmten Bereich. Analog zur Direktive Files, die Sie weiter oben bereits kennengelernt haben, gilt die folgende Direktive – der Name lässt es bereits erahnen – für Verzeichnisse: Options FollowSymLinks AllowOverride None
Zwischen den Schlüsselwörtern und befinden sich Einzeldirektiven, die für das mit der eröffnenden Directory-Direktive angegebene Verzeichnis gelten, in diesem Fall für das gesamte Wurzelverzeichnis des Webservers – sozusagen die Standardeinstellung für alle Verzeichnisse, in denen der Apache arbeitet. Für dieses Verzeichnis legt die Direktive Options FollowSymLinks fest, dass der Webserver symbolischen Links beim Ausspielen von Dateien folgen darf. Ob dies gewünscht ist oder nicht, muss jeder Anwender selbst entscheiden. Um die Übersichtlichkeit innerhalb des DocumentRoots nicht zu gefährden, ist der Verzicht auf Symlinks empfehlenswert. Die Direktive AllowOverride None legt fest, dass in .htaccess-Dateien stehende Direktiven keine Direktiven der zentralen Konfiguration überschreiben dürfen.
126
Apache
Oder anders: .htaccess-Dateien sind wirkungslos. Falls Sie wirklich .htaccess-Dateien verwenden möchten (denken Sie dabei bitte an meine Warnung aus Abschnitt 4.1.2!), können Sie durch Einsatz von AllowOverride gezielt festlegen, welche Konfigurationen in .htaccess-Dateien verwendet werden dürfen. Dazu kennt die Direktive AllowOverride fünf verschiedene Parameter: 왘
Options=...
Als Parameter sind alle Optionen der Direktive Options möglich. 왘
AuthConfig
Über .htaccess-Dateien kann ein Verzeichnisschutz eingerichtet werden. 왘
Limit
.htaccess-Dateien dürfen Order-Direktiven enthalten (Deny und Allow). 왘
FileInfo
Verschiedene Direktiven für die Behandlung von Dateitypen sind in .htaccessDateien erlaubt. Das umfasst sowohl Fehlerdokumente als auch das Festlegen von Dateitypen. 왘
Indexes
Verschiedene Direktiven für die Behandlung von Verzeichnissen sind erlaubt, also Direktiven, mit denen die Verarbeitung von Verzeichnissen durch den Apache geregelt wird. Feine Rechte Sie können durch die Verwendung von AllowOverride in Directory-Direktiven genau festlegen, in welchen Verzeichnissen .htaccess-Dateien erlaubt sind. Bedenken Sie aber, dass der Apache trotzdem bei jedem Request nach einer .htaccess-Datei sucht. Der Performanceverlust bleibt also der gleiche, egal ob .htaccess-Dateien für das Verzeichnis, aus dem der Apache den aktuellen Request bedient, erlaubt sind oder nicht.
Im nächsten Directory-Abschnitt legt die Ubuntu-Konfiguration gezielt die Berechtigungen für das DocumentRoot fest: Options Indexes FollowSymLinks MultiViews AllowOverride None Order allow,deny allow from all
Die drei letzten Direktiven sollten Ihnen bekannt vorkommen, da sie bereits in der zentralen Konfigurationsdatei enthalten sind. Neu ist der Options-Parameter Multiviews. Dahinter verbirgt sich eigentlich eine clevere Idee. Damit kann der Apache eine von einem Client angefragte Datei oder ein Verzeichnis auch dann
127
4.1
4
Serverdienste
finden, wenn der vom Client übergebene Datei- oder Verzeichnisname nicht korrekt ist. Angenommen, der Client fragt nach der Datei /admin.php, während im DocumentRoot aber nur ein Verzeichnis /admin/ vorhanden ist, dann wird der Apache für die Anfrage dank Multiviews das Verzeichnis /admin/ für die Beantwortung der Anfrage verwenden. Gibt es mehrere auf die ursprüngliche Anfrage passende Dateien oder Verzeichnisse, sucht der Apache diejenige bzw. dasjenige, der bzw. dem der Name der Anfrage am ehesten entspricht. Dabei gibt er als MIME-Typ in der Antwort den MIME-Typ der Datei zurück, die er als die passende ausgewählt hat. Multiviews bringen eine Menge Eigenleben in eine Website, und Sie sollten gut überlegen, ob Sie dieses Feature nutzen möchten. Es kann Webdesigner bei der Implementierung mehrsprachiger Websites entlasten, aber im Grunde genommen kann man dies durch modulare Programmierung viel besser lösen. Vor allen Dingen kann man sich damit ungewollt Probleme einfangen, zumindest beim Einsatz von Apache 1.x. Der Apache liefert per Multiview gefundenen Dateien mit dem für diese Dateien gültigen MIME-Type an den Client. Wenn der Client diesen MIME-Type nicht akzeptiert, wird er die Antwort des Servers zurückweisen. Das ist genau dann schlecht, wenn der Client nur den MIME-Type text/html akzeptiert, der Apache über die Multiview-Direktive eine PHP-Seite zurückliefert, und diese den MIMEType application/x-http-php hat. Falls Sie sich fragen, warum dies ein Problem darstellen soll, da doch alle modernen Browser andere MIME-Types als text/ html akzeptieren, muss ich Ihnen recht geben. Allerdings gibt es einen Client namens Googlebot, der ein Problem mit anderen MIME-Types als text/html hat. Falls Sie Google also eine problemlose Indizierung Ihrer Website ermöglichen wollen, sollten Sie über den Einsatz von Multiviews gut nachdenken. Wie oben bereits erwähnt: Multiviews bringen eine Logik in den Webserver, die nicht immer auf Anhieb durchschaubar ist. Falls Sie nicht genau wissen, ob Sie Multiviews benötigen, sollten Sie darauf verzichten. Die nächste Direktive definiert das Verzeichnis, in dem der Apache CGI-Skripte findet und ausführen darf. CGI – das Common Gateway Interface – ist eine mittlerweile in die Jahre gekommene Schnittstelle von Webservern, über die externe Skripte ausgeführt werden können. Diese Skripte müssen sich in einem genau definierten Verzeichnis befinden, damit der Apache sie ausführen darf. Ausführen bedeutet, dass der Apache einen neuen Prozess startet und in diesem Prozess das jeweilige Skript ausführt. Skripte können beliebige auf dem Betriebssystem ausführbare Dateien sein. ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
128
Apache
Das erste Argument der Direktive ist der Pfad, unter dem ein Client das CGI-Verzeichnis aufrufen kann. Das zweite Argument ist der tatsächliche Pfad des CGIVerzeichnisses im Dateisystem, in dem der Apache die CGI-Skripte ausführen darf. CGI – Alte Technik Der Nachteil des CGI beim Ausführen von dynamischen Aktionen auf dem Webserver liegt auf der Hand: Für jeden Aufruf eines CGI-Skriptes muss der Apache einen eigenen, neuen Prozess starten. Das kostet Zeit und Speicherplatz und ist daher auf vielbesuchten Webservern nicht zu empfehlen. Wesentlich sinnvoller sind Lösungen, die als ApacheModul zur Verfügung stehen, da dabei der Umweg über den Aufruf von externen Prozessen entfällt (z. B. PHP, mod_perl etc.). Darüber hinaus sind CGI-Skripte immer wieder Einfallstore für Angriffe gewesen, da durch die freie Programmierung in einer beliebigen Programmiersprache Sicherheitslücken aller Art in ein CGI-Skript gelangen können. Mit suEXEC stellt der Apache zwar eine Möglichkeit zur Verfügung, CGI-Skripte mit anderen Rechten als seinen eigenen auszuführen, dies ist aber nur ein schwacher Trost und beseitigt nicht das grundsätzliche Problem des CGI. Wenn es irgendwie geht, sollten Sie daher einen großen Bogen um CGI machen.
Das Zuweisen eines Verzeichnisses zu einem CGI-Link über die Direktive ScriptAlias allein erlaubt dem Apache noch nicht das Ausführen von CGI-Skripten in
diesem Verzeichnis. Dazu muss dieses Verzeichnis über eine entsprechende Direktive erst noch mit den notwendigen Optionen versehen werden. Dies erledigt in der Ubuntu-Konfiguration der folgende Block: AllowOverride None Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch Order allow,deny Allow from all
Wichtig an dieser Stelle ist die Option +ExecCGI. Diese legt fest, dass in dem betreffenden Verzeichnis das Ausführen von Skripten erlaubt ist. Des Weiteren sind für das CGI-Verzeichnis Multiviews verboten (sehr gut!). Gerade bei Skripten sollte man den Apache nicht selbständig aussuchen lassen, welche Datei er ausführen soll. Wenn für andere Teile des DocumentRoots Multiviews schon erlaubt sind, müssen sie aus Sicherheitsgründen wenigstens für das CGI-Verzeichnis verboten sein. Sofern die Standardeinstellung für das DocumentRoot das Verarbeiten von Symlinks vorsieht (FollowSymlinks), sollte im CGI-Verzeichnis unbedingt die Option +SymLinksIfOwnerMatch gesetzt sein, so wie es bei Ubuntu der Fall ist. Dadurch prüft der Apache, ob die Rechte der Zieldatei oder des Zielverzeichnisses eines Sym-
129
4.1
4
Serverdienste
links denen des Symlinks selbst entsprechen. Damit können Sie verhindern, dass ein Angreifer durch falsch gesetzte Rechte beim Ziel eines Symlinks diesem ein anderes Programm unterschieben bzw. das Programm selbst manipulieren kann. SymLinksIfOwnerMatch ist teuer. Die Sicherheit, die Sie durch die Option SymLinksIfOwnerMatch gewinnen, ist teuer erkauft. Bei jedem Zugriff auf das mit dieser Option versehende Verzeichnis prüft der Apache zunächst die Rechte des Verzeichnisses mit Hilfe des Systemaufrufes lstat(). Anschließend prüft er für die im Request angegebene Datei selbst mit lstat() die Zugriffsrechte. Das bedeutet, dass für jeden Request zwei zusätzliche Systemaufrufe und Dateisystemzugriffe erfolgen. Bei Hochlastservern ist dieser Faktor nicht zu vernachlässigen, weswegen Sie Symlinks und damit auch SymLinksIfOwnerMatch nur dann aktivieren sollten, wenn Sie wirklich Symlinks benötigen.
Im weiteren Verlauf der Konfiguration werden die ErrorLog- und die CustomLogDatei sowie der Loglevel des Apache gesetzt: ErrorLog /var/log/apache2/error.log LogLevel warn CustomLog /var/log/apache2/access.log combined
Interessanterweise wird an dieser Stelle die Signatur des Apache deaktiviert. Man darf sich zu Recht fragen, warum sie in der Hauptkonfigurationsdatei aktiviert und in der Datei des Hauptservers deaktiviert ist. ServerSignature Off
Im letzten Teil der Konfiguration befindet sich noch ein Alias auf das Standardverzeichnis, das die Apache-Konfiguration enthält. Alias /doc/ "/usr/share/doc/"
Das Verzeichnis selbst ist mit den oben besprochenen und nun bekannten Direktiven konfiguriert. Einzig die Allow-Direktive schränkt den Zugriff der Dokumentation auf Zugriffe vom lokalen Loopback-Interface (127.0.0.1) ein. Im Rahmen einer umfangreichen Serverhärtung sollten sich auf einem Produktivsystem aber ohnehin keine Standardverzeichnisse und -dateien befinden, weswegen Sie die Apache-Dokumentation nach der Installation umgehend entsorgen sollten. Die Dokumentation ist auf der Website des Apache-Projektes zu finden und muss nicht auf einem eigenen Server liegen. Standardverzeichnisse deuten in der Regel immer auf fehlende Systemhärtung hin, weswegen ein Angreifer im ersten Schritt immer nach genau solchen Daten sucht. Options Indexes MultiViews FollowSymLinks AllowOverride None
130
Apache
Order deny,allow Deny from all Allow from 127.0.0.0/255.0.0.0 ::1/128
Virtuelle Hosts bei Ubuntu und Gentoo Bei Ubuntu und Gentoo ist die Konfiguration virtueller Hosts aus der zentralen Konfigurationsdatei in separate Konfigurationsdateien ausgelagert. Bei Ubuntu liegen diese im Verzeichnis … /etc/apache2/mods-enabled … und bei Gentoo im Verzeichnis … /etc/apache2/vhosts.d/ Bei beiden Distributionen gibt es für jeden virtuellen Host im betreffenden Verzeichnis eine eigene Konfigurationsdatei. Über Include-Direktiven in den zentralen Konfigurationsdateien werden die einzelnen Konfigurationsdateien eingebunden.
Module Genau wie die Konfiguration virtueller Hosts werden bei Ubuntu und Gentoo die vom Apache zu verwendenden dynamischen Module durch separate Konfigurationsdateien – eine pro Modul – in entsprechenden Verzeichnissen konfiguriert. Bei Ubuntu ist dies das Verzeichnis /etc/apache2/mods-enabled, bei Gentoo /etc/ apache2/modules.d. Ein Unterschied besteht beim Laden der Module. Bei Ubuntu gibt es in diesem Verzeichnis pro Modul zwei Dateien. Die Datei <Modulname>.conf dient zur Konfiguration des betreffenden Moduls, die Datei <Modulname>.load enthält lediglich die Direktive LoadModule, mit der das betreffende Modul geladen wird. Im Beispiel von PHP5 enthält die Datei php5.conf die Konfiguration des Moduls: # cat php5.conf AddType application/x-httpd-php .php .phtml .php3 AddType application/x-httpd-php-source .phps
Die Datei php5.load weist den Apache an, das Modul zu verwenden: # cat php5.load LoadModule php5_module /usr/lib/apache2/modules/libphp5.so
Um ein Modul zu deaktivieren, müssen Sie also die LoadModule-Direktive in der betreffenden load-Datei auskommentieren. Unter Gentoo befindet sich zwar die Konfiguration der Module im obengenannten Verzeichnis, geladen werden die Module aber über LoadModule-Direktiven in
131
4.1
4
Serverdienste
der zentralen Konfigurationsdatei. Dies ist im Gegensatz zur Lösung unter Ubuntu weniger elegant, da bei Änderungen sowohl die Konfigurationsdatei des betreffenden Moduls als auch die zentrale Konfigurationsdatei angefasst werden müssen. Die Ubuntu-Methode ist da übersichtlicher, da Änderungen an Modulen komplett im Verzeichnis mods-enabled durchgeführt werden können.
4.1.3
SSL
HTTP ist ein Klartextprotokoll, das alle Daten unverschlüsselt überträgt. Jeder, der auf den Netzwerkverkehr zwischen Client und Server Zugriff hat, kann die übertragenen Daten mitlesen. Zwischenstationen gibt es in der Regel viele: das lokale WLAN, in das sich ein Angreifer eingeklinkt haben kann, die Router beim eigenen Provider, die Router bei den Providern, über die der Netzwerkverkehr geroutet wird, Administratoren, Strafverfolgungsbehörden, Dunkelmänner, die Liste kann beliebig erweitert werden. Und auch wenn der Satz »Nur wer etwas zu verbergen hat, braucht Verschlüsselung.« mittlerweile zum Zeitgeist zu gehören scheint, gehören sensible und insbesondere personenbezogene Daten einfach nicht in fremde Hände. Personenbezogene Daten sind vor allen Dingen Zugangsdaten zu Onlinediensten – vom Onlinebanking über Ebay bis zu Foren, in denen man sich mit Gleichgesinnten austauscht. Abbildung 4.5 zeigt den Mitschnitt einer Anmeldeseite, die unverschlüsselt per HTTP zwischen Client und Webserver übertragen wurde. Die Anmeldedaten liegen im Klartext vor (Benutzer klaus und Passwort pass1234). In dieser Form kann jeder der obengenannten Personen an jeder der obengenannten Stellen Ihre Daten mitlesen. Und auch wenn Sie nichts zu verbergen haben, unangenehm ist es trotzdem, wenn plötzlich jemand unter Ihrem Namen Online-Auktionen tätigt oder Postings in Foren veröffentlicht. Genauso peinlich kann es werden, wenn jemand die Zugangsdaten zu Ihrem CMS 3 mitschneidet, mit dem Sie den Inhalt Ihrer Webseite pflegen. Spätestens wenn Ihre Website nicht mehr den eigentlichen Inhalt ausliefert, sondern möglicherweise strafrechtlich relevante Parolen oder Links zu Konkurrenzfirmen, werden Sie den Nutzen einer verschlüsselten Kommunikation zu schätzen lernen. Dieses Buch kann und darf keine Anleitung zum Stehlen von Zugangsdaten sein, aber Beispiele dafür, wie man mit Programmen wie dsniff und einer WLAN-Karte in öffentlichen Hotspots beliebige Zugangsdaten aus Klartextprotokollen erhalten kann, gibt es im Internet zuhauf – es ist leichter als man denkt, weswegen das Übertragen von sensiblen Daten über HTTP keine gute Idee ist.
Als einfache, kostengünstige und effiziente Alternative zur unverschlüsselten Übertragung von Daten über HTTP gibt es das Protokoll HTTPS.4 HTTPS ist nichts anderes als ein mit SSL/TLS abgesichertes HTTP-Protokoll. Um HTTPS verwenden zu können, benötigt der Benutzer einen HTTPS-fähigen Browser, wozu alle modernen Browser gehören. Auf der Serverseite muss der Administrator den Server entsprechend konfigurieren und mit einem SSL-Zertifikat versehen. Mit diesem Zertifikat nach dem X.509-Standard identifiziert sich der Webserver beim Client, so dass der Client sicher sein kann, dass er mit dem richtigen Server spricht. Darüber hinaus läuft die gesamte folgende Kommunikation verschlüsselt ab. Neben den üblichen Serverzertifikaten erlaubt HTTPS auch den Einsatz von Client-Zertifikaten, mit denen sich ein Client einem Server gegenüber authentifizieren kann. HTTPS läuft traditionell über den TCP-Port 443, kann aber auch auf anderen Ports verwendet werden. SSL versus TLS SSL (Secure Sockets Layer) ist eine Erfindung von Netscape und wurde 1994 in der Version 1.0 veröffentlicht. SSL 2.0 erschien kurze Zeit später. 1999 wurde SSL im RFC 2246 unter dem Namen TLS (Transport Layer Security) als Standard veröffentlicht.
Obwohl durch die Standardisierung der eigentliche Name TLS ist, wird auch heutzutage in der Regel von SSL gesprochen. Funktional unterscheiden sich SSL 3.0 und TLS kaum. In diesem Buch werden beide Begriffe synonym verwendet.
4.1.4
SSL mit Ubuntu
In den Zeiten vor Apache 2.2 war das Einbinden von SSL in den Apache eine Qual. Realisiert wurde dies über das Modul mod_ssl vom OpenSSL-Projekt. 4 http://tools.ietf.org/html/rfc2818
133
4.1
4
Serverdienste
Modul und Apache-Version mussten immer genau zusammenpassen, das Übersetzen war nur mit Tricks möglich, und ist eine Änderung am Modul erfolgt, musste der ganze Apache neu kompiliert werden. Nicht zuletzt deswegen findet man heute noch viele ältere Apache-Webserver mit altem SSL-Modul. Kein Administrator hat Spaß daran, mod_ssl in den Apache zu kompilieren. Glücklicherweise gehört mod_ssl beim Apache 2.2 zu den Standardmodulen und muss nicht mehr separat übersetzt und eingebunden werden. Unter Ubuntu und Gentoo können Sie SSL mit wenigen Handgriffen aktivieren. Dieser Abschnitt zeigt die Einrichtung von SSL unter Ubuntu, der folgende Abschnitt die Einrichtung unter Gentoo. Der erste Schritt bei der Einrichtung eines SSL-fähigen Apache ist das Erzeugen eines SSL-Zertifikates im X.509-Format. Da die Zertifikatsdatei an einem sicheren, d. h. für lokale und entfernte Benutzer unzugänglichen Ort abgelegt sein muss, wird in diesem Abschnitt dafür das neu anzulegende Verzeichnis /etc/apache2/ssl verwendet: # mkdir /etc/apache2/ssl
Im ersten Schritt erstellen Sie mit dem Programm OpenSSL das Zertifikat. Ist OpenSSL noch nicht installiert, kann das mit … # sudo apt-get install openssl
... geschehen. Die Grundlage der Zertifikatserstellung ist die Erzeugung eines Serverschlüssels. Mit diesem Schlüssel können Sie ein selbsterstelltes Zertifikat signieren oder eine offizielle Anfrage zur Ausstellung eines Zertifikates bei einer zertifikatsausgebenden Stelle wie Thawte5 oder CAcert6 stellen. Den Schlüssel erzeugen Sie über den folgenden Befehl (alle folgenden Befehle müssen Sie entweder mit sudo oder als root ausführen): # cd /etc/apache2/ssl # openssl genrsa -out server.key -des3 2048 Generating RSA private key, 2048 bit long modulus ..................................+++ .....+++ e is 65537 (0x10001) Enter pass phrase for server.key: Verifying - Enter pass phrase for server.key:
5 http://www.thawte.de/ 6 http://www.cacert.org/
134
Apache
Entgegen anderslautender Anleitungen im Internet sollten Sie den Schlüssel immer mit einem Passwort versehen. Webserver können kompromittiert werden, und wenn ein Angreifer in den Besitz von Zertifikaten und Schlüsseln gelangt, die nicht mit Passwörtern geschützt sind, kann er diese ohne Probleme benutzen. Nach Abschluss des obenstehenden Befehls finden Sie im aktuellen Verzeichnis (/etc/apache2/ssl) die Datei server.key, Ihren privaten Schlüssel. Der Schlüssel hat eine Schlüssellänge von 2048 Bit. Die ersten Zeilen des Schlüssels sollten das folgende Format haben: # cat server.key -----BEGIN RSA PRIVATE KEY----Proc-Type: 4,ENCRYPTED DEK-Info: DES-EDE3-CBC,0188B27641A92734 [...]
Mit diesem Key erzeugen Sie nun ein X.509-Zertifikat, das später vom Apache für die Identifizierung verwendet wird. Bitte beachten Sie, dass ein selbstgebautes X.509-Zertifikat im Browser beim Benutzer stets eine Fehlermeldung verursachen wird. Der Grund dafür liegt im Konzept von SSL bzw. X.509 als Verschlüsselungssystem. X.509 setzt eine so genannte Public-Key-Infrastruktur (PKI) voraus. Darunter versteht man ein verteiltes, aus verschiedenen Komponenten bestehendes System, mit dem Vertrauensstellungen bei der Verwendung von Public-Key-Kryptographie hergestellt werden können. Unter Public-Key-Kryptographie versteht man asymmetrische Verschlüsselung, bei der ein Kommunikationspartner Nachrichten an einen anderen Kommunikationspartner mit dessen öffentlichem Schlüssel verschlüsselt. Der Empfänger kann diese Nachrichten mit seinem privaten, vor allen anderen Kommunikationsteilnehmern geheim gehaltenen Schlüssel entschlüsseln. Der große Vorteil der asymmetrischen Kryptographie ist, dass zwischen Kommunikationsteilnehmern keine geheimen Schlüssel ausgetauscht werden müssen. Jeder Kommunikationsteilnehmer benötigt nur die öffentlichen Schlüssel der anderen zum ver- und seinen eigenen Schlüssel zum entschlüsseln. Der Nachteil dieser Form der Verschlüsselung ist, dass sich die Kommunikationspartner untereinander nicht zwingend kennen und vertrauen können. Die Kenntnis über einen öffentlichen Schlüssel eines Kommunikationspartners verschafft noch keine Sicherheit, dass sich hinter diesem Schlüssel auch der Kommunikationspartner verbirgt, der er zu sein vorgibt. Eine PKI schafft dieses Problem aus der Welt, indem alle Kommunikationsteilnehmer eine zentrale Instanz, die Zertifizierungsinstanz oder CA (Certificate Au-
135
4.1
4
Serverdienste
thority) als vertrauenswürdig akzeptieren. Im WWW wird diese Vertrauensstellung dadurch realisiert, dass die gängigen Browser die öffentlichen Schlüssel bekannter CAs eingebaut haben. Im Firefox finden Sie eine Liste der CAs unter Einstellungen 폷 Erweitert 폷 Verschlüsselung 폷 Zertifikate anzeigen (siehe Abbildung 4.6). Eine CA erstellt oder signiert Zertifikate. Durch diese Signatur bestätigt die CA, dass ein betreffendes Zertifikat glaubwürdig ist. Ein Browser, der von einem Webserver ein Zertifikat übergeben bekommt, das von einer akzeptierten CA ausgestellt oder signiert ist, wird dieses Zertifikat ohne Fehlermeldung annehmen. Anders sieht es aus, wenn das Zertifikat nicht von einer bekannten CA erstellt oder zertifiziert ist. Dann wird der Browser darauf hinweisen, dass zwar ein Zertifikat vorliegt, die Identität des Zertifikatinhabers aber nicht überprüft werden kann. Nehmen Sie solche Meldungen ernst, wenn sie Ihnen im Internet begegnen. Ein nicht von einer offiziellen CA ausgestelltes oder signiertes Zertifikat ist nichts wert! Leider kosten von offiziellen CAs ausgestellte oder signierte Zertifikate Geld, so dass für den Eigengebrauch ein selbsterstelltes Zertifikat herhalten muss. So lange keine Kunden mit diesem Zertifikat arbeiten müssen, gefährdet das die Sicherheit nicht.
Abbildung 4.6
136
Im Firefox bekannte CA-Instanzen
Apache
Ein eigenes Zertifikat erstellen Sie mit dem nachfolgenden Befehl. Die einzugebenden Daten können Sie frei wählen, wichtig ist allerdings, dass der Common Name der Name des Webservers ist, auf dem das Zertifikat laufen soll. Die Identifizierung des Servers erfolgt bei SSL über den FQDN (Fully qualified Domain Name). # openssl req -new -x509 -days 365 -key server.key -out server.crt Enter pass phrase for server.key: You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----Country Name (2 letter code) [AU]:DE State or Province Name (full name) [Some-State]:NRW Locality Name (eg, city) []:Cologne Organization Name (eg, company) [Internet Widgits Pty Ltd]:Foo Ltd. Organizational Unit Name (eg, section) []:Webservices Common Name (eg, YOUR name) []:www.foo.bar Email Address []:[email protected]
Die zu Beginn abgefragte Passphrase ist die Ihres obenerzeugten Schlüssels. Nach Abschluss des Dialogs befindet sich im aktuellen Verzeichnis neben dem privaten Schlüssel auch noch das Zertifikat selbst (server.crt). Da von der Sicherheit der Daten die Sicherheit Ihres SSL-Services abhängt, sollten Sie die Daten unbedingt vor unbefugtem Zugriff schützen: # chmod 700 /etc/apache2/ssl # chmod 600 /etc/apache2/ssl/*
Der Inhalt der Zertifikatsdatei ist in der vorliegenden Form recht nichtssagend, über das Programm openssl können Sie aber prüfen, ob das Zertifikat die gewünschten Daten enthält: # openssl x509 -text -inform pem -in server.crt |more Certificate: Data: Version: 3 (0x2) Serial Number: 93:a9:bf:f3:32:cc:b9:91 Signature Algorithm: sha1WithRSAEncryption Issuer: C=DE, ST=NRW, L=Cologne, O=Foo Ltd.,
137
4.1
4
Serverdienste
OU=Webservices, CN=www.foo.bar/[email protected] Validity Not Before: Jun 22 17:33:43 2008 GMT Not After : Jun 22 17:33:43 2009 GMT Subject: C=DE, ST=NRW, L=Cologne, O=Foo Ltd., OU=Webservices, CN=www.foo.bar/[email protected] Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public Key: (2048 bit) Modulus (2048 bit): 00:b1:75:6c:5f:17:a1:86:a9:13:7b:9b:c4:a6:96: 2d:2c:95:59:e4:22:36:08:e6:38:0c:0c:12:51:f4: 6b:25:b8:fe:d1:d6:bc:ba:34:f9:10:67:97:37:9d: 61:38:81:a1:21:cd:d6:23:25:1a:74:84:71:ec:e1: 04:ce:f4:15:42:24:26:2e:67:f1:34:32:ff:17:c6: [...]
Nach dem Erzeugen des Zertifikates müssen Sie den Apache entsprechend konfigurieren. Dazu aktivieren Sie im ersten Schritt das SSL-Modul des Apache. Unter Ubuntu geht das mit dem folgenden Befehl: # a2enmod ssl Module ssl installed; run /etc/init.d/apache2 force-reload to enable.
Dieses Skript erzeugt die entsprechenden symbolischen Links im Verzeichnis /etc/apache2/mods-enabled: ssl.conf -> ../mods-available/ssl.conf ssl.load -> ../mods-available/ssl.load
Die Ports-Direktive des Apache ist so konfiguriert, dass beim aktivierten SSLModul automatisch auch Port 443 geöffnet wird. Diese Einstellung finden Sie in der Datei /etc/apache2/ports.conf, Sie brauchen an dieser Stelle also nichts zu verändern: Listen 80 Listen 443
Da der Ubuntu-Apache standardmäßig mit virtuellen Hosts arbeitet, erzeugen Sie für den SSL-Betrieb einen neuen virtuellen Host, indem Sie aus dem Verzeichnis /etc/apache2/sites-available/ von der Datei default eine Kopie mit Namen ssl erzeugen: # cp /etc/apache2/sites-available/default /etc/apache2/sitesavailable/ssl
138
Apache
In dieser Datei müssen Sie den virtuellen Host über die Direktiven NameVirtualHost und VirtualHost an den Port 443 binden: NameVirtualHost *:443
Innerhalb der VirtualHost-Direktive aktivieren Sie SSL und übergeben das Zertifikat und den Schlüssel: SSLEngine On SSLCertificateFile /etc/apache2/ssl/server.crt SSLCertificateKeyFile /etc/apache2/ssl/server.key
Damit der virtuelle Host in eigene Logdateien schreibt, müssen Sie die beiden Direktiven ErrorLog und CustomLog noch anpassen: ErrorLog /var/log/apache2/error_ssl.log CustomLog /var/log/apache2/access_ssl.log combined
Speichern Sie die Datei, und aktivieren Sie den virtuellen Host mit dem Befehl a2ensite: # a2ensite ssl Site ssl installed; run /etc/init.d/apache2 reload to enable.
Mit diesem Befehl wird ein symbolischer Link im Verzeichnis /etc/apache2/sitesenabled erzeugt: 000-default -> /etc/apache2/sites-available/default ssl -> /etc/apache2/sites-available/ssl
Vor dem Start des Apache müssen Sie in der Konfiguration des Default-Servers noch zwei Direktiven anpassen, damit dieser nicht auf allen Ports lauscht, sondern nur auf Port 80. Anderenfalls würde der SSL-Dienst nicht funktionieren und der Apache beim Start eine Fehlermeldung ausgeben. Ändern Sie dazu in der Datei /etc/apache2/sites-enabled/000-default die ersten beiden Zeilen: NameVirtualHost *:80
Schon wieder geschlampt! Auch an dieser Stelle gilt: Wäre die Apache-Konfiguration unter Ubuntu etwas sorgfältiger ausgefallen, würde das einem unbedarften Benutzer Ärger ersparen. Dadurch, dass der Standard-Host nicht an Port 80 gebunden ist, schlägt das Starten des SSL-Apache fehl, solange man nicht die Konfiguration des Standard-Hosts ändert. Ärgerlich und überflüssig!
139
4.1
4
Serverdienste
Jetzt können Sie den Apache starten: # /etc/init.d/apache2 start * Starting web server apache2 apache2: Could not reliably determine the server's fully qualified domain name, using 127.0.1.1 for ServerName Apache/2.2.8 mod_ssl/2.2.8 (Pass Phrase Dialog) Some of your private key files are encrypted for security reasons. In order to read them you have to provide the pass phrases. Server 127.0.1.1:443 (RSA) Enter pass phrase: OK: Pass Phrase Dialog successful. ...done.
Ja, er fragt jetzt bei jedem Start nach der Passphrase. Und ja, das ist gut so. Ein Zertifikat oder Schlüssel ohne Passphrase in den falschen Händen kann fatale Folgen haben. Von jetzt an ist der Apache auch per HTTPS erreichbar. Beim Aufruf im Browser erscheint die obenangekündigte Fehlermeldung (Abbildung 4.7). Damit macht der Browser darauf aufmerksam, dass das Zertifikat nicht von einer als vertrauenswürdig eingestuften CA erzeugt oder unterschrieben ist.
Abbildung 4.7 Fehlermeldung beim Aufruf per HTTPS
140
Apache
Wenn Sie sich die Details des Zertifikates ansehen, sollten Ihnen die dort angezeigten Daten bekannt vorkommen (Abbildung 4.8). Akzeptieren Sie dieses Zertifikat, kann es sein, dass eine weitere Meldung darauf aufmerksam macht, dass der im Zertifikat hinterlegte Name nicht mit dem des Servers übereinstimmt (Abbildung 4.9). Das kann dann passieren, wenn Sie – wie ich in diesem Beispiel – einen beliebigen Namen verwenden, der aber nicht dem des Servers entspricht. Um die Gültigkeit des Namens zu überprüfen, vergleicht der Browser den im Request verwendeten Namen mit dem im Zertifikat gespeicherten Namen. Stimmen beide überein, gibt es keine Fehlermeldung, der Server ist als derjenige identifiziert, der im Zertifikat steht.
Abbildung 4.8
Details des SSL-Zertifikates
Abbildung 4.9
Der CN stimmt nicht mit dem Hostnamen überein.
141
4.1
4
Serverdienste
Nachdem Sie alle Meldungen gelesen und bestätigt haben, sind Sie am Ziel: Der Apache spricht HTTPS. SSL kostet. Denken Sie bitte daran, dass SSL angewandte Kryptographie ist. Der Server hat durch die Verschlüsselung im SSL-Betrieb eine wesentlich höhere CPU-Last als im normalen HTTP-Betrieb. Neben dem erhöhten Speicherverbrauch durch das SSL-Modul sollten Sie daher bei stark frequentierten Websites mit SSL-Unterstützung immer die CPU-Auslastung im Auge behalten.
4.1.5
SSL mit Gentoo
Unter Gentoo verläuft die Einrichtung von SSL für den Apache analog. Im ersten Schritt müssen Sie den Apache und OpenSSL installieren (sofern nicht bereits geschehen): # emerge apache2 openssl
Das Gentoo-Paket bringt einen Beispiel-Schlüssel und ein Beispiel-Zertifikat mit. Beide liegen im Verzeichnis /etc/apache2/ssl. Beide Dateien (server.crt und server.key) können Sie löschen, da im Folgenden die Erstellung eines neuen Schlüssels und eines neuen Zertifikates gezeigt wird. Zunächst erstellen Sie den Serverschlüssel und versehen ihn mit einem Passwort. Über den vorletzten Parameter können Sie den Verschlüsselungsalgorithmus ändern. In Abschnitt 4.1.4 kam DES3 zum Einsatz, im folgenden Beispiel ist dies AES256. Kryptographie ist ein weites Feld. Beim Hantieren mit kryptographischen Funktionen und Programmen kann Unwissenheit häufig mehr Schaden anrichten, als durch den Nutzen dieser Programme und Funktionen erwächst. Falls Sie nicht genau wissen, welcher Parameter welchen Zweck hat und welcher Algorithmus welche Vor- und Nachteile mit sich bringt, sollten Sie entweder Standardeinstellungen verwenden oder einschlägige Recherchen betreiben. Ein guter Anfang im Bereich der Kryptographie ist das Buch »Applied Cryptography« der Krypto-Koryphäe Bruce Schneier.
Den Schlüssel erzeugen Sie analog zum Vorgehen unter Ubuntu: # cd /etc/apache2/ssl # openssl genrsa -out server.key –aes256 2048
142
Apache
Der Inhalt des Schlüssels sieht gut aus: # cat server.key |more -----BEGIN RSA PRIVATE KEY----Proc-Type: 4,ENCRYPTED DEK-Info: AES-256-CBC,203F2EF693739F65E71879BEF0E9903E [...]
Das Erzeugen des Zertifikates erfolgt ebenfalls analog. Denken Sie daran, dass der Common Name dem Namen des Servers entsprechen muss. # openssl req -new -x509 -days 365 -key server.key -out server.crt Enter pass phrase for server.key: You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----Country Name (2 letter code) [AU]:DE State or Province Name (full name) [Some-State]:NRW Locality Name (eg, city) []:Cologne Organization Name (eg, company) [Internet Widgits Pty Ltd]:Foo Ltd. Organizational Unit Name (eg, section) []:Webservices Common Name (eg, YOUR name) []:www.foo.bar Email Address []:[email protected]
Auch hier zeigt eine Überprüfung, dass das Zertifikat erfolgreich mit den richtigen Daten angelegt worden ist: # openssl x509 -text -inform pem -in server.crt |more Certificate: Data: Version: 3 (0x2) Serial Number: f5:55:f3:b8:c2:80:48:f8 Signature Algorithm: sha1WithRSAEncryption Issuer: C=DE, ST=NRW, L=Cologne, O=Foo Ltd., OU=Webservices, CN=www.foo.bar/[email protected] Validity Not Before: Jun 23 18:53:10 2008 GMT Not After : Jun 23 18:53:10 2009 GMT Subject: C=DE, ST=NRW, L=Cologne, O=Foo Ltd.,
143
4.1
4
Serverdienste
OU=Webservices, CN=www.foo.bar/[email protected] Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public Key: (2048 bit) Modulus (2048 bit): 00:f8:4c:c6:e6:f1:da:89:3d:f3:86:35:5d:f5:fc: 7b:e8:b4:fc:b3:e1:b3:0e:fb:cd:40:51:83:da:2b: 89:20:96:19:ee:e9:bc:6d:3f:b9:3a:eb:af:d5:7e:
Nach diesem Schritt sind Sie bereits fertig! Der Gentoo-Apache unterstützt von Hause aus SSL und ist dementsprechend vorkonfiguriert. Sie müssen nach der Installation des Paketes lediglich die Dummy-Dateien für den Schlüssel und das Zertifikat durch eigene Dateien ersetzen. Nach dem Neustart des Apache meldet sich dieser mit dem obenerstellten Zertifikat. Systemstart mit Tücken Sobald der Apache mit SSL-Zertifikat und -Schlüssel ausgestattet ist, verlangt er beim Start nach dem Passwort des Schlüssels. Das bedeutet, dass er danach auch beim Systemstart fragt, sofern er automatisch geladen wird – etwas umständlich, dafür aber sicher.
4.1.6
PHP
Der Apache ist installiert, SSL eingerichtet, jetzt fehlt noch eine Möglichkeit, dynamische Webseiten veröffentlichen zu können. In der Linux-Welt ist dies in der Regel PHP, eine Skriptsprache, die Mitte der 90er Jahre von Rasmus Lerdorf entwickelt wurde. Damals war CGI die Standardschnittstelle für die Erzeugung dynamischer Aktionen auf einem Webserver, und als Programmiersprache kam meistens Perl zum Einsatz. Diese Lösung war zwar für Programmierer sehr komfortabel – konnten sie damit doch ihre gesammelten Programmierkenntnisse in CGI-Skripte packen –, die Einbindung von Perl als Programmiersprache hat allerdings einen entscheidenden Nachteil. Das Gerüst bildet bei dieser Art der dynamischen Programmierung Perl selbst. Das heißt, dass der HTML-Code, der für das Layout der Webseite verwendet wird, in Perl-Skipte eingebettet wird. Alle HTML-Ausgaben, die vom Webserver an den Webbrowser des Benutzers ausgeliefert werden sollen, müssen über Perl-Befehle ausgegeben werden. Allein die Ausgabe einer horizontalen Linie, in HTML ein einfaches , ist aufwendig, wie das folgende Beispiel zeigt: #!/usr/bin/perl -w use strict; print “Foo”; print “”; print “”;
144
Apache
Dieselbe Ausgabe in HTML, ohne Perl, ist wesentlich einfacher: Foo
Das Problem ist offensichtlich: Ein Webdesigner muss seinen Layout-Code in ein Perl-Skript einbetten. Da ein Webdesigner aber in der Regel kein Programmierer ist, bedeutet das Verschmelzen von Layout und Programmierung für ihn eine aufwendige Sache, insbesondere bei umfangreichen Skripten mit viel Layout und Programmierung. Aus diesem Grund hat sich Perl bei Webdesignern als Skriptsprache nie richtig durchsetzen können, und PHP konnte seinen Siegeszug antreten, denn es folgt dem umgekehrten Ansatz. Anstatt Layout in die Programmierung basteln zu müssen, wird bei PHP die Programmierung in ein fertiges Layout eingebettet. Das hat den Vorteil, dass ein Webdesigner eine Seite komplett layouten und der Programmierer anschließend die Programmierung in das fertige Layout einbauen kann. PHP läuft als Apache-Modul (kann aber auch über die CGI-Schnittstelle angesprochen werden) und parst Dateien mit PHP-Code in HTML-Dateien, die an die Clients eines Webservers ausgeliefert werden. Das vorstehende Beispiel so modifiziert, dass das aktuelle Datum ausgegeben wird, sieht in PHP wie folgt aus: Foo echo date("m.d.Y"); ?>
Das HTML-Gerüst ist dasselbe wie bei einer reinen HTML-Datei. Der Unterschied ist, dass in der PHP-Datei das Einfügen von PHP-Code möglich ist. So kann ein Programmierer eine fertig layoutete HTML-Seite nachträglich mit Code und damit mit Dynamik füllen. Vom Webbrowser abgerufen, interpretiert der Apache – genauer gesagt das in den Apache geladene PHP-Modul – den PHP-Code in der Seite und bettet das Ergebnis in HTML ein. Das Ergebnis der Beispieldatei zeigt Abbildung 4.10.
Abbildung 4.10
PHP-Datei im Webbrowser
145
4.1
4
Serverdienste
Installation unter Ubuntu Die Installation von PHP unter Ubuntu ist simpel: # sudo apt-get install php5
Anschließend können Sie das Modul mit dem Befehl … # sudo a2enmod php5
… aktivieren. Im Verzeichnis /etc/apache2/mods-enabled werden dadurch symbolische Links auf die Dateien /etc/apache2/mods-available/php5.conf und /etc/ apache2/mods-available/php5.load erzeugt. Wie beim SSL-Modul dient die .confDatei der Konfiguration des PHP-Moduls, die .load-Datei enthält die Direktive LoadModule zum Laden des PHP-Moduls. Der Inhalt der .conf-Datei ist überschaubar: AddType application/x-httpd-php .php .phtml .php3 AddType application/x-httpd-php-source .phps
Die Direktive IfModule prüft das Vorhandensein des PHP5-Moduls und legt – sofern das Modul geladen ist – die Datei-Endungen fest, anhand derer der Apache PHP-Dateien identifizieren kann. Standardmäßig sind das die Endungen .php, .phtml und .php3. Die letztgenannte Endung existiert aus historischen Gründen. Die erste produktiv einsetzbare Version von PHP war die Version 3, zu ihrer Zeit als PHP3 bekannt. Die damals für PHP-Dateien bevorzugte Datei-Endung war .php3. Dies änderte sich erst mit Erscheinen der PHP-Version 4. Da kamen die ersten Entwickler ins Grübeln und begannen, die Datei-Endung von der PHP-Version abzukoppeln. Im Grunde genommen können Sie beliebige Endungen für PHP-Dateien verwenden, allerdings spricht allein aus Gründen der Übersichtlichkeit viel für den Einsatz von Standards oder Best Practices. Anhänger der Philosophie Security through Obscurity, also des Herbeiführens von Sicherheit durch das Verschleiern von Informationen, geben PHP-Dateien auf ihrem Webserver die Endung .asp und hoffen, Angreifer dadurch verwirren zu können, dass sie ihnen auf diese Weise einen Internet Information Server mit ASP-Dateien vorgaukeln. Mein Tipp: Sorgen Sie lieber für eine vernünftige Systemhärtung und sichere Programmierung, dann können Sie sich solche billigen Tricks sparen. Nach dem Aktivieren des Moduls müssen Sie den Apache neu starten und können dann PHP-Dateien verwenden. Die simpelste aller PHP-Seiten, sozusagen das
146
Apache
»Hallo Welt«-Programm der PHP-Programmierung, ist eine Seite, die nur die PHP-Funktion phpinfo() enthält: phpinfo(); ?>
Diese Funktion gibt umfangreiche Informationen über das System aus (siehe Abbildung 4.11).
Abbildung 4.11
Ausgabe der Funktion »phpinfo()«
Installation unter Gentoo Unter Gentoo können Sie durch das Setzen von USE-Flags festlegen, mit welchen Funktionen Sie PHP ausstatten möchten. Entweder setzen Sie die Flags global in der Datei /etc/make.conf oder der Einfachheit halber einfach über die Umgebungsvariable USE. In diesem Fall müssen Sie PHP aber in derselben Shell oder in einer Subshell installieren, in der Sie die Variable deklariert haben: export USE=“apache2 mysql ssl xml“
147
4.1
4
Serverdienste
Die Flags apache2 und mysql sollten Sie in jedem Fall setzen, da in Abschnitt 4.2.1 aus dem Apache, MySQL und PHP ein Lamp-System gebaut wird. Über … emerge php
… starten Sie die Installation von PHP. Dies kann in Abhängigkeit von den aktivierten Flags eine Weile in Anspruch nehmen. Auf einer Intel Core 2 Duo mit 2,16 GHz und 2 GB Hauptspeicher dauert das Übersetzen und Installieren knapp eine halbe Stunde: real user sys
32m17.291s 12m39.400s 17m56.230s
Nach Abschluss des Emerge-Vorgangs ist PHP bereits komplett installiert und konfiguriert. Prüfen Sie, ob in der Datei /etc/conf.d/apache2 PHP5 als Startparameter für den Apache eingetragen ist, wenn nicht, fügen Sie den Parameter -D PHP5 zur Variablen APACHE2_OPTS hinzu: APACHE2_OPTS="-D DEFAULT_VHOST -D INFO -D LANGUAGE -D SSL -D SSL_ DEFAULT_VHOST -D PHP5"
Im Verzeichnis /etc/apache2/modules.d befindet sich nach der Installation die Datei 70_mod_php5.conf, mit der das PHP-Modul geladen und konfiguriert wird: # Load the module first LoadModule php5_module modules/libphp5.so # Set it to handle the files AddType application/x-httpd-php .php AddType application/x-httpd-php .phtml AddType application/x-httpd-php .php3 AddType application/x-httpd-php .php4 AddType application/x-httpd-php .php5 AddType application/x-httpd-php-source .phps DirectoryIndex index.php index.phtml
Die Konfiguration von Gentoo zeigt eine Alternative zu der von Ubuntu. Die IfDefine-Direktive in der ersten Zeile wertet die Parameter aus, die dem Apache
148
Apache
beim Start mit dem Parameter -D übergeben werden. Diese werden unter Gentoo in der Datei /etc/conf.d/apache2 festgelegt.
Die erste Zeile der Konfiguration prüft also auf das Vorhandensein des Parameters PHP5 und führt bei einem positiven Ergebnis der Überprüfung die zwischen und befindlichen Direktiven aus. Die folgende Direktive prüft, ob das Modul mod_php5 bereits geladen ist. Ist dies nicht der Fall, wird es über die Direktive LoadModule geladen. Das Ausrufezeichen vor dem Modulnamen in der Überprüfung negiert diesen, die Bedingung heißt im Klartext daher »Wenn das Modul mod_php5.c nicht geladen ist …«.
Die LoadModule-Direktive kennen Sie bereits aus der Ubuntu-Konfiguration, sie erledigt nichts anderes, als das betreffende Modul zu laden. Die nächste Direktive führt eine weitere Überprüfung durch:
In Abhängigkeit vom Vorhandensein des Moduls mod_mime, mit dem der Apache erst in die Lage versetzt wird, Dateitypen anhand von Datei-Endungen zu bestimmen, werden im Folgenden mit den AddType-Direktiven die Datei-Endungen definiert, die der Apache als PHP-Dateien interpretieren soll. Die Direktive DirectoryIndex am Ende der Konfiguration bestimmt die Dateitypen, die der Apache als Indexdateien in einem Verzeichnis verwendet, wenn ein Benutzer nur den Verzeichnisnamen aufruft, nicht aber einen Dateinamen (z. B. http://www.galileo-press.de/). Die Indexdateien sind in diesem Fall die Dateien index.php und index.phtml. DirectoryIndex index.php index.phtml
Starten Sie den Apache neu, und legen Sie im DocumentRoot (Standard ist unter Gentoo das Verzeichnis /var/www/localhost/htdocs) eine PHP-Datei ab – im Zweifelsfall eine mit der PHP-Funktion phpinfo(), denn diese gibt Informationen aus, die Sie zum Härten und Konfigurieren des Systems noch benötigen werden.
149
4.1
4
Serverdienste
Abbildung 4.12
Es klappt – PHP unter Gentoo.
PHP absichern PHP ist eine mächtige Programmiersprache und bietet Programmierern und Angreifern umfangreiche Möglichkeiten. Daher sollte man eine PHP-Installation tunlichst härten, bevor man sie produktiv nutzt. Die Erfahrung zeigt, dass das nachträgliche Härten von PHP-Installationen so gut wie unmöglich ist, wenn erst einmal individuell entwickelte PHP-Applikationen auf dem System laufen. Entwickler haben selten einen Blick für Sicherheit, und Entwicklersysteme sind häufig wenig restriktiv konfiguriert. Daher gehen Entwickler meist von der größten anzunehmenden Menge von Möglichkeiten auf einem System aus. Werden Produktivsysteme dann im Nachhinein gehärtet, führt das meist dazu, dass die darauf laufenden PHP-Applikationen nicht mehr laufen. Daher mein Tipp: Härten Sie Ihren Server direkt nach der Installation, und bevor die erste Applikation läuft. Machen Sie den Entwicklern strenge Vorgaben und halten Sie diese auch selbst ein. Der Großteil aller Angriffe richtet sich mittlerweile nicht mehr gegen Betriebssysteme und Serverdienste von Webservern, sondern gegen die Webappli-
150
Apache
kationen, die auf den Servern laufen. Von daher ist beim Produktivbetrieb von Webanwendungen größte Vorsicht geboten. Die zentrale Konfigurationsdatei von PHP ist die Datei php.ini. Wo sich diese Datei befindet, gibt die Funktion phpinfo() aus. Rufen Sie einfach die von Ihnen angelegte Testseite mit dieser Funktion auf. In der Zeile Loaded Configuration File sehen Sie dann den Ort der Datei. Unter Gentoo ist das /etc/php/apache2-php5/ php.ini und unter Ubuntu /etc/php5/apache2/php.ini. Die Datei php.ini ist eine grundsätzlich selbsterklärende Konfigurationsdatei. Jede Direktive ist mit einem ausführlichen und gut verständlichen Kommentar versehen. Untersuchen Sie die Datei auf eigene Faust, und passen Sie diese an Ihre Bedürfnisse an. Bestimmte PHP-Applikationen verlangen bestimmte Einstellungen, d. h., die Konfiguration wird sich in der Regel nach den Anforderungen der Applikationen richten. Nichtsdestotrotz gibt es einige Direktiven, die unmittelbare Auswirkungen auf die Sicherheit von PHP haben. Diese Direktiven werden im Folgenden erklärt und sollten auf einem Produktivsystem nur in Ausnahmefällen geändert werden. Nach der Änderung an der php.ini müssen Sie das PHP-Modul neu laden, was einen Neustart des Apache bedeutet. Direktive
Bedeutung
safe_mode
Der Safe Mode von PHP deaktiviert eine Reihe von als potentiell gefährlich angesehenen Funktionen und prüft bei Datei- und Verzeichnisoperationen, ob die Zieldatei dem Benutzer gehört – wie auch das PHP-Skript, das diese Operationen ausführt. In der kommenden PHP-Version 6 wird es keinen Safe Mode mehr geben.
safe_mode_gid
Führt bei aktiviertem Safe Mode dazu, dass PHP neben der UID auch die GID von Skript und Zieldatei vergleicht.
safe_mode_include_ dir
Bei aktiviertem Safe Mode führt PHP bei Dateien aus mit dieser Direktive angegebenen Verzeichnissen keine Überprüfung von UID und GID durch.
safe_mode_exec_dir
Ist der Safe Mode aktiviert, dürfen nur Programme und Skripte in den mit dieser Direktive konfigurierten Verzeichnissen von PHPSkripten aus aufgerufen werden (gilt für die Funktionen exec() und passthru()).
safe_mode_allowed_ env_vars
Der Wert dieser Variablen sollte grundsätzlich PHP_ sein, da PHPSkripte damit nur ihre eigenen Umgebungsvariablen bearbeiten dürfen. Ist kein Wert gesetzt, darf ein PHP-Skript jede Umgebungsvariable verändern.
Tabelle 4.2 Sicherheitsrelevante PHP-Direktiven
151
4.1
4
Serverdienste
Direktive
Bedeutung
safe_mode_ protected_env_vars
Mit dieser Direktive kann eine Liste von Umgebungsvariablen definiert werden, die von PHP-Skripten nicht geändert werden dürfen.
disable_functions
Akzeptiert eine Liste von PHP-Funktionen als Parameter, die nicht ausgeführt werden dürfen. Auf einem Produktivsystem sollte z. B. die Funktion phpinfo() grundsätzlich nicht erlaubt sein, da diese einem Angreifer wertvolle Informationen über das System liefern kann. Und Testdateien mit phpinfo()-Aufrufen finden sich auf Produktivsystemen leider häufiger, als erwartet. Aber auch Funktionen für Dateisystem-Zugriffe und das Ausführen von Programmen müssen auf einem Produktivsystem nicht zwingend möglich sein. Hier gilt es, kritisch zu prüfen, was notwendig ist und was nicht. Mit dieser Direktive können Sie erheblichen Einfluss auf die Sicherheit von PHP nehmen.
disable_classes
Analog zu disable_functions, bezieht sich aber auf den objektorientierten Ansatz von PHP und erlaubt das Definieren von Klassen, deren Verwendung verboten ist.
expose_php
PHP erweitert den Server-String des Apache um Angaben über PHP. Da sämtliche Informationen über Systeminterna zumindest ein Informations-Leak darstellen, sollte diese Direktive auf off stehen.
memory_limit
Übermäßiger Speicherverbrauch aufgrund schlechter Programmierung oder durch Ausnutzen von Programmierfehlern durch einen Angreifer können schnell zum Stillstand des Servers führen. Mit dieser Direktive kann der maximal erlaubte Speicherverbrauch pro PHP-Skript definiert werden. Beziehen Sie den Wert dieser Direktive auch bei Tuningmaßnahmen mit in Ihre Überlegungen ein (siehe dazu auch Abschnitt 4.1.7). Verbraucht ein PHP-Skript mehr als die erlaubte Menge an Speicher, wird seine Ausführung abgebrochen. Wichtig ist, dass ein Skript die Einstellung dieser Direktive ändern kann, wenn der Safe Mode nicht aktiv ist.
max_execution_time
Diese Direktive legt die maxmiale Zeit in Sekunden fest, die ein PHP-Skript laufen darf. Damit können Probleme durch unendlich lange laufende Skripte vermieden werden. Solche kann ein Angreifer für Denial-of-Service-Angriffe nutzen. Läuft ein PHPSkript länger als der definierte Zeitraum, wird seine Ausführung abgebrochen.
max_input_time
Ähnlich der vorstehenden Direktive, legt aber nur den Zeitraum fest, den ein Skript für das Parsen von Request-Daten zur Verfügung hat. Überschreitet ein Skript die definierte Zeit, wird seine Ausführung abgebrochen.
Ein Produktivsystem sollte grundsätzlich keine Fehlermeldungen ausgeben oder zumindest nicht an die Benutzer. Fehlermeldungen können sensible Daten enthalten, die einem Angreifer Informationen über Systeminterna liefern können. Mit dieser Direktive können Sie die Ausgabe von Fehlermeldungen steuern. Der Parameter off deaktiviert alle Fehlermeldungen, stderr leitet alle Fehlermeldungen nach stderr um, on nach stdout.
display_startup_ errors
PHP kann während seiner Startphase bereits Fehler ausgeben. Dies sollte auf einem Produktivsystem grundsätzlich nicht erfolgen, weswegen diese Direktive auf off stehen sollte.
register_globals
In den Frühzeiten von PHP konnte ein Benutzer über GET-Parameter alle Variablen eines Skriptes überschreiben. Dies stellte natürlich eine erhebliche Sicherheitslücke dar. Seit einigen Jahren ist dieses Verhalten standardmäßig deaktiviert, wozu diese Direktive auf off stehen muss. Selbst wenn es eine Applikation verlangt oder ein Entwickler noch so sehr darum bettelt: Aktivieren Sie niemals register_globals, denn das ist der beste Angriffsvektor für einen Angreifer.
post_max_size
Eine weitere Direktive zur Beschränkung von Ressourcen. Damit kann die von PHP akzeptierte Größe von POST-Daten begrenzt werden. Der Standardwert ist 8 MB, was für ein Produktivsystem schon relativ viel ist. In der Praxis kommen Sie wahrscheinlich mit wesentlich weniger aus.
magic_quotes_gpc
Ist diese Direktive aktiviert, werden bei GET- und POST-Requests sowie in Cookies einfache und doppelte Anführungszeichen, Backslashes und NULL-Bytes automatisch escaped. Sehr nützlich, ist in PHP 6 allerdings nicht mehr vorhanden.
file_uploads
PHP bietet Funktionen zum Upload von Dateien. Über solche Funktionen kann sich ein Angreifer nach der Kompromittierung einer Webapplikation eine Datei-Schnittstelle zum System schaffen. Sofern Sie keine Upload-Funktion in PHP benötigen, sollten Sie mit dieser Direktive Datei-Uploads verbieten. Dies kann allerdings auch über disable_functions geschehen.
upload_tmp_dir
Sind Datei-Uploads erlaubt, verwendet PHP für das Zwischenspeichern der Uploaddaten das temporäre Verzeichnis des Betriebssystems. Um die PHP-Umgebung vom restlichen System besser abkoppeln zu können, können Sie mit dieser Direktive ein eigenes temporäres Verzeichnis definieren.
upload_max_ filesize
Gibt die maximal zulässige Größe für ein Datei-Upload in Megabyte an.
Mit dieser Direktive kann das Öffnen von Dateien per HTTP-Aufruf unterbunden werden. In der Vergangenheit war diese Art der Datei-Einbindung häufig ein Angriffsvektor, da ein Angreifer über diese Funktionalität eigenen Code in kompromittierte PHPAnwendungen einschleusen konnte. Falls nicht benötigt, sollte diese Funktionalität deaktiviert werden.
allow_url_include
Entspricht der Direktive allow_url_fopen, bezieht sich aber auf das Einbinden (»Include«) von Dateien per HTTP oder FTP.
open_basedir
Mit dieser Direktive können Sie ein Verzeichnis definieren, in dem und unterhalb dessen sich alle Dateisystem-Operationen von PHP abspielen müssen. Außerhalb dieses Verzeichnisses sind keine Dateisystemoperationen erlaubt. Vergleichbar mit einer Chroot-Umgebung, allerdings wird dies innerhalb von PHP realisiert, nicht durch das Betriebssystem.
Die Möglichkeiten, über die php.ini Sicherheit von PHP-Anwendungen herzustellen oder zu erzwingen, sind äußerst beschränkt und grob. Sie können damit eine einigermaßen stabile Plattform schaffen – um weitere Härtungsmaßnahmen kommen Sie aber nicht herum. Das betrifft insbesondere eine sichere Programmierung von PHP-Anwendungen. Mittlerweile steht mit der PHP-Erweiterung Suhosin eine weitere Möglichkeit zur Verfügung, PHP sicher(er) zu konfigurieren. Der folgende Abschnitt zeigt den Einsatz von Suhosin. Reichweite der Direktiven Beachten Sie, dass die Direktiven in der php.ini nur für PHP-Dateien auf dem Webserver gelten! Alle anderen vom Webserver ausgelieferten Dateitypen, HTML-Dateien, CGISkripte etc., sind von den Einstellungen nicht betroffen, für diese Dateitypen müssen Sie daher andere Sicherheitsvorkehrungen treffen.
Suhosin Suhosin – wer fühlt sich bei diesem Namen nicht an eine chinesische Mahlzeit erinnert – ist ein koreanisches Wort und bedeutet übersetzt »Schutzengel«. So steht es zumindest auf der Website des Suhosin-Projektes. Suhosin ist neben seiner eigentlichen Bedeutung auch der Name eines Projektes zur Härtung von PHP. Hervorgegangen ist es aus dem Hardened-PHP-Projekt. Suhosin besteht aus zwei Teilen. Der für die Benutzer und Programmierer offensichtlichste Teil ist die PHP-Erweiterung. Über diese Erweiterung lassen sich sehr genau Sicherheitsparameter festlegen und definieren. Damit können Sie die PHP-
154
Apache
Funktionalität beschränken oder verbieten – der ideale Weg, Diskussionen mit Programmierern zu provozieren. Der andere Teil von Suhosin ist ein Patch für den PHP-Kern, der diesen vor Implementierungsfehlern im Kern selbst wie z. B. Buffer Overflows schützen soll. Beide Teile sind unabhängig voneinander und können bei Bedarf auch einzeln verwendet werden. Angesichts der Mächtigkeit von PHP und dem leider immer noch sehr wenig verbreiteten Sicherheitsbewusstsein unter Programmierern ist die Verwendung der PHP-Erweiterung in jedem Fall angezeigt. Im Hinblick auf die in der Vergangenheit bekanntgewordenen Sicherheitslücken in der PHP-Implementierung sollte das Suhosin-Patch ebenfalls auf keinem Server fehlen. Unter Ubuntu ist der Patch für den PHP-Kern standardmäßig aktiviert (Pluspunkt!). Dies verrät die phpinfo-Funktion (siehe Abbildung 4.13). Um die PHPErweiterung von Suhosin zu aktivierten, installieren Sie das Paket php5-suhosin: # sudo apt-get install php5-suhosin
Abbildung 4.13
Das Suhosin-Patch unter Ubuntu
Nach der Installation meldet phpinfo auch das Vorhandensein der Erweiterung (siehe Abbildung 4.14).
Abbildung 4.14
PHP-Erweiterung nach Installation von php5-suhosin
Unter Gentoo ist es etwas komplizierter. PHP kommt standardmäßig ohne Suhosin-Patch. Um diesen zu installieren, müssen Sie PHP mit dem USE-Flag suhosin emergen. Das bedeutet, entweder in der Datei /etc/make.conf die USE-Variable entsprechend zu erweitern oder für die Installation die Umgebungsvariable USE zu setzen. Die zweite Möglichkeit ist einfacher, birgt aber die Gefahr, dass bei einem Update das USE-Flag suhosin vergessen wird und der Apache anschließend ohne den PHP-Patch läuft. Für welche der beiden Varianten Sie sich auch entscheiden, nach Setzen des USE-Flags muss PHP neu emerged werden: emerge php
155
4.1
4
Serverdienste
Der PHP-Patch wird dabei automatisch angewendet. Die PHP-Erweiterung von Suhosin verbirgt sich im gleichnamigen Paket, allerdings existieren für Gentoo zwei Suhosin-Pakete, eins für PHP 4 und eins für PHP 5. Portage macht mit einer entsprechenden Meldung auf diesen Umstand aufmerksam: # emerge suhosin Calculating dependencies \ !!! The short ebuild name "suhosin" is ambiguous. Please specify !!! one of the following fully-qualified ebuild names instead: dev-php4/suhosin dev-php5/suhosin
Um die Erweiterung für PHP 5 zu installieren, nehmen Sie den kompletten Paketnamen und führen damit ein Emerge durch: emerge dev-php5/suhosin
Nach einem Neustart des Apache sind jetzt auch unter Gentoo der PHP-Patch und die PHP-Erweiterung aktiv (siehe Abbildung 4.15).
Abbildung 4.15
Suhosin-Patch und -Erweiterung unter Gentoo
Konfiguriert wird Suhosin über eine eigene Konfigurationsdatei. Welche Datei das ist, verrät ebenfalls phpinfo(). Unter Ubuntu ist das standardmäßig die Datei /etc/php5/apache2/conf.d/suhosin.ini, unter Gentoo /etc/php/apache2-php5/extactive/suhosin.ini. Während die Konfigurationsdatei unter Gentoo vorbildlich kommentiert ist und für jede Direktive den Text der Suhosin-Dokumentation aufführt, enthält sie unter Ubuntu nur die Direktiven ohne jegliche Kommentierung, was das schnelle Anpassen von Einstellungen extrem mühsam macht. Bei beiden Distributionen sind sämtliche Direktiven auskommentiert. Das entspricht der Philosophie von Suhosin, die besagt, dass die Standardkonfiguration für die meisten Benutzer vollkommen ausreichend ist. Die wohl wichtigste Direktive in der Konfiguration von Suhosin ist suhosin.simulation. Damit weisen Sie Suhosin an, alle Aktivitäten zu loggen, aber keine Aktivitäten auszuführen. Auf diese Weise können Sie kontrollieren, an welchen Stel-
156
Apache
len Suhosin in die Ausführung Ihrer PHP-Applikation eingreifen würde, und entsprechende Maßnahmen treffen. Entweder passen Sie die Suhosin-Konfiguration an (schlecht!) oder Ihre Applikation (gut!). Auf einem Produktivsystem sollte Suhosin nie im Simulationsmodus laufen. Dieser ist ideal für ein Testsystem, denn dort können Sie Änderungen an Applikation und System vornehmen, ohne dass ein Angreifer Zugriff auf das System hat und Sicherheitslücken ausnutzen kann. Im Netzwerkbereich verfährt man ähnlich. Bei der Einführung einer Firewall oder von neuen Firewall-Regeln aktiviert man zunächst nur das Logging und überprüft dann nach einer gewissen Beobachtungszeit anhand der Logdaten, welche der neuen Regeln aktiv geworden sind. Die Konfiguration von Suhosin ist in fünf Bereiche gegliedert: Logging Configuration, Executor Options, Misc Options, Transparent Encryption Options und Filtering Options. Die Logging Configuration umfasst verschiedene Direktiven, mit denen das Logging von sicherheitsrelevanten Ereignissen durch Suhosin gesteuert werden kann. Sofern Sie keine besonderen Anforderungen an die Logausgaben von Suhosin stellen, lässt sich mit den Standardeinstellungen gut leben. Bei der Einbindung in ein Logsystem, z. B. in einen zentralen Syslog-Server, kann es allerdings hilfreich sein, Log-Facility und Log-Level anzupassen. Die entsprechenden Direktiven finden Sie in diesem Bereich. Interessant wird es im Bereich der Executor Options. Im Folgenden sind die wichtigsten Direktiven aufgeführt und erläutert. Eine vollständige Übersicht über alle Direktiven enthalten die Suhosin-Konfigurationsdatei von Gentoo und die Website des Suhosin-Projektes.7 Direktive suhosin... Bedeutung ...executor.max_ depth
Maximale bei der Ausführung eines PHP-Skriptes erlaubte Stack-Tiefe. Durch moderates Anpassen dieses Parameters können zu stark verschachtelte Skripte erkannt und an der Ausführung gehindert werden.
...executor. include.max_ traversal
Ein beliebter Angriff auf Webapplikationen ist der Path-Traversal-Angriff. Dabei nutzt ein Angreifer fehlende Filterungen von Eingaben aus und manipuliert den Pfad einer inkludierten Datei. Über beliebig tiefe Manipulationen können so mitunter Systemdateien eingelesen werden (z. B.: ../../../../etc/shadow). Mit dieser Direktive kann die maximale Anzahl von ../ im Pfad einer inkludierten Datei festgelegt werden. Damit können Sie verhindern, dass ein Angreifer über die angegriffene Include-Direktive eine Datei außerhalb des DocumentRoots einlesen kann.
Tabelle 4.3 Suhosin-Direktiven im Bereich der »Executor Options« 7 http://www.hardened-php.net
157
4.1
4
Serverdienste
Direktive suhosin... Bedeutung ...executor. include.whitelist
Definiert eine Whitelist von Dateien, die über include- oder require-Direktiven eingebunden werden dürfen. Für höchstmögliche Sicherheit ist das Verwenden der Whitelist der beste Weg, da nur explizit freigegebene Dateien verwendet werden dürfen. Ist keine Whitelist definiert, wird die folgende Direktive ausgewertet.
...executor. include.blacklist
Das Gegenteil der vorstehenden Direktive: Damit können Sie Dateien definieren, die nicht über include oder require eingebunden werden dürfen. Blacklists lassen sich leicht umgehen und sind daher kein probates Mittel für wirksame Sicherungsmaßnahmen. Sind weder White- noch Blacklist definiert, sind alle URL-Schemata für die Einbindung von Dateien verboten.
...executor. func.whitelist
Eine Liste von PHP-Funktionen, deren Verwendung erlaubt ist. Diese Liste zu pflegen ist viel Arbeit, ermöglicht aber eine ideale Kontrolle über das PHP-System. Wenn keine Funktionen in der Whitelist stehen, kommt die folgende Direktive zur Auswertung.
...executor. func.blacklist
Das Pendant zu disable_functions in der php.ini. Hier gilt dassselbe wie für suhosin.executor.include.blacklist: Blacklists sind leicht zu umgehen, weswegen die Verwendung von Whitelists wesentlich sinnvoller ist.
...executor. disable_eval
Die eval()-Funktion von PHP ist böse, böse und obendrein böse. eval() interpretiert einen übergebenen String als Code und führt diesen Code aus. In der Vergangenheit hat diese Funktion durch mangelnde Überprüfung und Filterung des Strings immer wieder zu schweren Sicherheitslücken geführt. Daher sollte die Verwendung von eval() grundsätzlich verboten sein. Dazu muss diese Direktive gesetzt sein.
Tabelle 4.3 Suhosin-Direktiven im Bereich der »Executor Options« (Forts.)
Im Bereich der Misc Options ist insbesondere die Direktive suhosin.simulation wichtig, deren Sinn zu Anfang dieses Abschnittes bereits erläutert worden ist. Daneben ist die Direktive suhosin.memory_limit interessant, mit der Sie den Speicherverbrauch eines Skriptes verbindlich festlegen können. Läuft PHP nicht im Safe Mode, kann ein Skript den in der php.ini definierten Wert für memory_limit überschreiben. Mit der Direktive suhosin.memory_limit können Sie zwei Dinge festlegen: Übergeben Sie 0 als Parameter, darf ein Skript nie mehr Speicher verbrauchen, als bei seinem Aufruf über memory_limit (in der php.ini) festgelegt ist. Die Änderungen von memory_limit durch ein Skript sind dadurch ungültig, da nur der initial definierte Speicher zur Verfügung steht.
158
Apache
Geben Sie als Parameter einen Wert größer 0 an, definiert dieser den Speicherplatz in Megabyte, den ein Skript mehr als den in der php.ini festgelegten Wert verbrauchen darf. Auf diese Weise können Sie ein Soft- und ein Hardlimit definieren, mit dem kurzfristig erhöhter Speicherbedarf kontrolliert geregelt werden kann. Im nächsten Konfigurationsbereich von Suhosin, den Transparent Encryption Options, können Sie verschiedene Parameter zur Verschlüsselung von Sessions und Cookies setzen. Da dies keine allgemeingültigen Einstellungen sind und maßgeblich vom jeweiligen Anwendungsfall abhängen, sollten Sie diese Direktiven in Abhängigkeit von Ihren spezifischen PHP-Applikationen untersuchen. Der interessanteste und umfangreichste Konfigurationsbereich von Suhosin sind die Filtering Options. In diesem Bereich befinden sich alle Direktiven, mit denen Input-Validation zentral automatisiert und gesteuert werden kann. Viele Direktiven ähneln sich, weswegen in der folgenden Tabelle nur die wichtigsten exemplarisch aufgeführt sind. Eine vollständige Liste enthalten die Konfigurationsdatei von Suhosin unter Gentoo und die Online-Dokumentation. Direktive suhosin... Bedeutung ...filter.action
Mit dieser Direktive können Sie festlegen, wie Suhosin auf die Verletzung einer Filterregel reagiert. Mögliche Reaktionen sind das simple Blockieren der gefilterten Variablen (Standardverhalten), die Rückgabe eines HTTP-Codes samt Weiterleitung des Besuchers zu einer anderen URL ([302], http:// www.galileo-press.de) oder das Aufrufen eines anderen Skriptes ([402], /var/www/panic.php).
...cookie.disallow_ nul
Führt zum Ausfiltern von Null-Bytes in einem Cookie. Es gibt noch weitere Direktiven zum Ausfiltern von Null-Bytes in POST- und GET-Requests. Angreifer bauen häufig Null-Bytes in Anfragen an Webserver ein, um Fehlermeldungen zu provozieren.
...cookie.max_name_ length
Legt die maximale Länge von Variablen-Namen in Cookies fest.
...cookie.max_value_ Legt die maximale Größe von Variablen in Cookies fest. length ...request.max_vars
Maximale Anzahl von Variablen, die in einem Cookie, einer URL oder einem POST-Request registriert werden dürfen.
...upload.max_ uploads
Mit dieser Direktive können Sie die maximale Anzahl von Uploads festlegen, die in einem Request stattfinden dürfen.
Tabelle 4.4 Einige Direktiven der Filtering Options von Suhosin
159
4.1
4
Serverdienste
Direktive suhosin... Bedeutung ...upload.disallow_ binary
Der Upload von Binärdaten ist in den seltensten Fällen erwünscht und kann mit dieser Direktive unterbunden werden. Das hilft natürlich nicht gegen den Upload von PHP-Skripten, mit denen man als Angreifer genauso viel Unfug anstellen kann wie mit Binärdaten. Diese Direktive entbindet daher in keinem Fall von der Überprüfung von hochgeladenen Dateien auf Schadroutinen.
...upload. verification_script
Wenn Sie Uploads verwenden, denken Sie an meine Warnung zur vorstehenden Direktive, und überprüfen Sie hochgeladene Dateien. Mit dieser Direktive können Sie ein Skript festlegen, das nach dem Hochladen zur Überprüfung der Dateien ausgeführt wird. Das Skript muss nach erfolgreicher Überprüfung als Rückgabewert »1« zurückliefern, ansonsten wird die hochgeladene Datei gelöscht.
...server.encode
Diese undokumentierte Direktive weist PHP an, schädliche Sonderzeichen in den Variablen REQUEST_URI und QUERY_ STRING zu escapen, d. h. unschädlich zu machen. Über solche Sonderzeichen sind Cross-Site-Scripting- und SQL-InjectionAngriffe möglich.
Tabelle 4.4 Einige Direktiven der Filtering Options von Suhosin (Forts.)
Die hier aufgeführten Direktiven zur Konfiguration von Suhosin sollten einen Überblick über die Fähigkeiten von Suhosin gegeben haben. Auch wenn Sie keine Lust oder kein Interesse an einer individuellen Härtung haben, sollten Sie Suhosin zumindest in der Standardkonfiguration verwenden, sowohl den Patch als auch die Erweiterung. Durch die Einbindung ins Paketmanagement bei Gentoo und Ubuntu stellt auch die Pflege von Suhosin keinen Mehraufwand dar. So oder so: Unterschätzen Sie nicht die Gefahr, die von ungehärteten Webservern und Webapplikationen ausgeht. Eine Website ist das Interface zu den Benutzern – und zu den Angreifern. Sicherheitslücken wie Cross-Site-Scripting oder SQL-Injection sind schwerwiegend, lassen sich aber mit einem minimalen Aufwand während der Entwicklung beheben. Achten Sie daher stets darauf, welche Applikationen Sie im Internet verwenden. Wenn Sie selbst programmieren, sollten Sie sich regelmäßig mit den häufigsten Angriffsvektoren gegen die von Ihnen eingesetzte Technologie auseinandersetzen. Auch wenn Sie auf Ihrem Webserver keine Online-Banking-Applikation betreiben: Harmlose und ungesicherte Websites werden immer häufiger von Angreifern als Ausgangsplattform für Angriffe auf Benutzer verwendet.
160
Apache
4.1.7
Tuning
Mit steigender Beliebtheit einer Website kommt der Betreiber – also Sie – schnell in die Verlegenheit, dass sein Webserver mehr Anfragen bearbeiten muss, als dieser eigentlich kann. Der Effekt ist, dass die Antwortzeiten des Webservers in den Keller gehen. Die Benutzer müssen länger auf die Antworten des Webservers warten, hämmern ungeduldig auf ihrer (F5)-Taste herum (Reload), bringen den Webserver damit noch mehr ins Schwitzen und verlassen schließlich entnervt Ihre Website. Damit ist das Lastproblem dann zwar gelöst, aber nicht zur Zufriedenheit aller Beteiligten. Wenn Sie den Webserver nicht nur zum Spaß betreiben, sondern um damit Geld zu verdienen, muss eine andere Lösung her. Programmierung Der erste Schritt ist das Programmieren bzw. Verwenden schlanker Webapplikationen. Schlank bedeutet nicht, dass Sie auf benötigte Features verzichten sollen, sondern, dass eine Webapplikation nicht verschwenderisch mit Ressourcen umgehen darf. Leider ist die Tugend einer effizienten Programmierung gerade im Webbereich nicht sehr weit verbreitet. Moderne Skript- und Programmiersprachen wie PHP, Java, Python etc. erlauben auch Einsteigern das Erstellen von Webapplikationen mit vielen Funktionen, wobei für Details wie optimierte Datenbankabfragen, geringe CPU-Belastung und geringer Speicherverbrauch mangels Erfahrung häufig der Blick fehlt. Das böse Erwachen kommt dann, wenn eine Webapplikation unter Last gerät und sich fehlende Optimierung dadurch bemerkbar macht, dass der Webserver zusammenbricht. Viele Entwickler lassen außer Acht, dass sich ein produktiver Server unter Last anders verhält als ein Testsystem, auf das nur der Entwickler selbst zugreift. Führt eine schlecht programmierte Webapplikation dann zum Stillstand eines Produktivsystems, ist die erste Antwort aus der Entwicklerecke meist »Bei mir funktioniert das aber ohne Probleme!«. Die Macht der Zahlen Anschaulich wird das Lastproblem durch ein kleines Rechenbeispiel. Stellen Sie sich die Startseite einer Website vor, deren Inhalt der Webserver beim Aufruf der Seite dynamisch aus Datenbankinhalten generiert. Der Entwickler der Seite war nicht zimperlich und hat dafür fünf SQL-Statements verwendet, die beim Aufruf der Seite vom Webserver an die Datenbank abgegeben werden. Darüber hinaus verbraucht der Webserver für jeden Prozess, der die Seite bearbeitet, 3 MB RAM. Auf dem Testsystem, auf das ein oder zwei Personen zugreifen, läuft die Seite performant, und der Webserver antwortet in einer akzeptablen Zeit.
161
4.1
4
Serverdienste
Der Entwickler befindet die Seite für gut und legt sie auf das Produktivsystem. Der Apache läuft in der Ubuntu-Standardkonfiguration und kann 1024 gleichzeitige Anfragen bearbeiten. Da die Website beliebt und bekannt ist, kommt es zum parallelen Aufruf der Seite durch 500 Benutzer. Das erzeugt 500*5 SQL-Statements und belegt 500*3 MB RAM. Auch wenn diese Rechnung den wahren Sachverhalt vereinfacht, zeigt sie jedoch die Änderung der Dimensionen beim Wechsel einer Webapplikation von einem Test- zu einem Produktivsystem.
Nun machen Aufbau und Programmierung einer Webapplikation in der Regel zwar den größten Teil bei Performanceproblemen eines Webservers aus, nichtsdestotrotz können Sie den Server selbst durch geeignete Tuning-Maßnahmen für den Betrieb optimieren. Dabei sollten Sie zunächst das Betriebssystem selbst einer Optimierung unterziehen und sich dann dem Apache widmen. Hardware und Betriebssystem Hinsichtlich der Ausstattung des Servers mit einer ausreichend schnellen CPU und ausreichend RAM gibt es keine allgemeingültige Faustregel. Aktuelle Mehrkern-CPUs sind aber auch für gehobene Lastansprüche durchaus ausreichend. Schön an der Technik der Webserver ist, dass sie sich sehr leicht skalieren lassen. Reicht ein Server nicht mehr aus, kann ein zweiter hinzugenommen werden. Über einen vorgeschalteten Loadbalancer – egal ob in Hard- oder Software realisiert – lassen sich dann die Anfragen der Clients auf die beiden (oder mehr) Webserver verteilen. Nicht zuletzt aus Redundanzgründen ist dies ein Standardaufbau für professionelle Websites. Nichtsdestotrotz ist eine gründliche Optimierung eines einzelnen Servers angezeigt, denn zum einen ist es unökonomisch, Leistung zu verschenken, und zum anderen hat nicht jeder Zeit, Geld und Lust, eine Website auf verschiedene Server zu verteilen. Der wichtigste Punkt in der Hardwareausstattung eines Webservers ist RAM. Während sich die Anforderungen an die CPU in der Regel in Grenzen halten und die CPU nur in seltenen Fällen oder bei komplizierter oder schlechter Programmierung so unter Dampf gerät, dass sie negative Auswirkungen auf die Performance des Webservers hat, macht sich zu knapper Hauptspeicher sofort bemerkbar. Der Server beginnt dann, Daten aus dem physikalischen Speicher in den virtuellen Speicher auszulagern, er swappt. Dadurch bricht die Performance so massiv ein, dass die Benutzer in ihren Webbrowsern keine Antworten des Webservers mehr in akzeptabler Zeit erhalten. Das Ergebnis ist in der Regel, dass die Benutzer die langsame Seite immer wieder erneut abrufen, was zu noch mehr Arbeit für den Webserver führt und diesen zu noch intensiverem Swapping zwingt. Diesem sich selbst verstärkenden Prozess können Sie nur durch ausreichend Hauptspeicher entgegenwirken. Des Weiteren müssen der Webserver und alle
162
Apache
anderen Serverdienste auf diesem System so konfiguriert sein, dass das Betriebssystem – zumindest rechnerisch – immer genügend physikalischen Speicher zur Verfügung hat. Speicherverbrauch Wenn Sie ausschließlich einen Webserver auf Ihrem System betreiben, ist das Errechnen des Speicherverbrauchs relativ einfach. Dazu müssen Sie herausfinden, wie viel Speicher ein einzelner Apache-Prozess benötigt. Anschließend passen Sie die Konfiguration des Apache entsprechend an, so dass diese nie mehr Prozesse erzeugen kann, als physikalischer Speicherplatz vorhanden ist. Die einfachste Art, den Speicherverbrauch der Apache-Prozesse herauszufinden, ist über das Kommando top. Über die Taste (<) können Sie nach dem Start des Programms die Anzeige der Prozesse sortieren. Drücken Sie die Taste so oft, bis top die Prozesse dem Namen nach sortiert, der Apache rückt dadurch ganz nach oben. Abbildung 4.16 zeigt die Prozesse des Standard-Apache unter Gentoo. Der Prozess mit der PID 13192 gehört dem Benutzer root und stellt den Vaterprozess dar, der sich an den Port 80 bindet und alle weiteren Prozesse erzeugt. Die Kindprozesse gehören alle dem Benutzer apache. Die interessanten Spalten in der Anzeige von top sind VIRT, RES und SHR. VIRT steht für den durch einen Prozess belegten virtuellen Speicher, RES für den durch einen Prozess belegten physikalischen Speicher und SHR für den von einem Prozess belegten gemeinsamen Speicher, den so genannten shared Memory. Der Vaterprozess belegt 9,5 MB virtuellen Speicher, 3,9 MB physikalischen Speicher und 2,3 MB shared Memory. Jeder Kindprozess belegt dieselbe Menge an virtuellem Speicher, 2,4 MB physikalischen Speicher und 0,9 MB shared Memory. Der interessante Wert an dieser Stelle ist der von den Kindprozessen belegte physikalische Speicher. Der Speicherverbrauch eines einzelnen Apache-Prozesses ist von den verwendeten Modulen abhängig. Ein schlanker Apache, der ohne Module ausschließlich statische Webseiten ausliefert, verbraucht z. B. wesentlich weniger Speicherplatz pro Prozess als ein Apache mit einkompiliertem PHP. Überlegen Sie daher immer, wie viel Funktionalität des Apache Sie wirklich benötigen. Je schlanker der Server bleibt, desto leistungsfähiger ist er. Wie in Abschnitt 4.1.1 beschrieben, ist es in Hochlastumgebungen sogar sinnvoll, in Abhängigkeit von den Anforderungen verschiedene Webserver zu verwenden – für dynamische Inhalte einen mit dem klassischen Forking-Modul, für statische Inhalte einen mit Multithreading.
163
4.1
4
Serverdienste
Abbildung 4.16
Apache-Prozesse ohne externe Module
Der Gentoo-Apache ist schlank kompiliert: # apache2 -l Compiled in modules: core.c prefork.c http_core.c mod_so.c
Die über die Konfiguration aktivierten Module erhalten Sie über den folgenden Befehl: # apache2 -t -D DUMP_MODULES Loaded Modules: core_module (static) mpm_prefork_module (static) http_module (static) so_module (static) actions_module (shared) alias_module (shared) auth_basic_module (shared) authn_alias_module (shared) authn_anon_module (shared) authn_dbm_module (shared) authn_default_module (shared) authn_file_module (shared) authz_dbm_module (shared)
Obwohl eine Vielzahl von Modulen aktiv ist, sind die Kindprozesse vergleichsweise schlank. Zum Vergleich zeigt Abbildung 4.17 den Speicherverbrauch des Ubuntu-Apache mit aktiviertem PHP5-Modul. Die Anzahl der einkompilierten Module hält sich auch hier in Grenzen: # apache2 -l Compiled in modules: core.c mod_log_config.c mod_logio.c prefork.c http_core.c mod_so.c
Auch ist die Anzahl der aktivierten Module überschaubar: # apache2 -t -D DUMP_MODULES Loaded Modules:
Allerdings schlägt das PHP5-Modul mit einem gewaltigen Ressourcenverbrauch zu Buche. Der Vaterprozess belegt 18,5 MB virtuellen Speicher, 5,6 MB physika-
166
Apache
lischen Speicher und 3,1 MB shared Memory. Jeder Kindprozess belegt ebenfalls 18,5 MB virtuellen Speicher und 3,1 MB physikalischen Speicher. Wie viel Speicher das PHP5-Modul verbraucht, können Sie einfach herausfinden, indem Sie die das Modul aktivierende Direktive in der Datei /etc/apache2/modsenabled/php5.load auskommentieren und den Apache neu starten. Das Ergebnis ist beachtlich (siehe Abbildung 4.18). Der Speicherverbrauch des Vaterprozesses ist um 44 % beim virtuellen Speicher zurückgegangen und um 55 % beim physikalischen Speicher. Bei den Kindprozessen beträgt die Einsparung ebenfalls 44 % beim virtuellen und 41 % beim physikalischen Speicher. Das zeigt zum einen, dass sich das Verschlanken der Apache-Konfiguration massiv auf den Ressourcenverbrauch des Servers auswirken kann; zum anderen veranschaulicht diese Rechnung, wie Sie den Speicherverbrauch des Webservers selbst errechnen können. Bei einem Speicherverbrauch von 3,1 MB pro Kindprozess legen Sie einen Server mit 2 GB Hauptspeicher schnell lahm, wenn der Apache 1024 Kindprozesse erzeugen darf und er diese Prozesse durch entsprechend viele Client-Zugriffe auch tatsächlich erzeugt. Rechnen Sie immer konservativ. Bei einer Maschine mit 2 GB Hauptspeicher sollte der Apache maximal 1 GB belegen dürfen. Das ergibt bei einem durchschnittlichen Speicherverbrauch pro Kindprozess von 3,1 MB knapp 600 Prozesse.
Abbildung 4.18
Ubuntu-Apache ohne PHP5-Modul
167
4.1
4
Serverdienste
Die in Abschnitt 4.1.2 beschriebene Direktive ServerLimit hat ebenfalls einen Einfluss auf den Speicherverbrauch des Apache, da sie nicht nur die maximalen Werte von MaxClients und ThreadLimit festlegt, sondern auch shared Memory reserviert. Abbildung 4.18 zeigt einen Apache, bei dem ServerLimit auf den tatsächlich verwendeten Wert (1024) eingestellt ist. Abbildung 4.19 zeigt denselben Apache mit einem ServerLimit von 20.000, dem im Quelltext hartkodierten Maximalwert. Der Verbrauch des physikalischen Speichers pro Prozess ist leicht erhöht, der Verbrauch des virtuellen Speichers hat sich hingegen um 50 % erhöht. Setzen Sie den ServerLimit daher immer nur genau so hoch, wie Sie ihn tatsächlich benötigen. Das spart wertvollen Speicher.
Abbildung 4.19
Apache mit einem »ServerLimit« von 20.000
Festplatten-I/O Neben dem verfügbaren physikalischen Speicher ist eine geschickte Partitionierung und bei Webservern mit extrem viel Festplatten-I/O auch die Wahl des Dateisystems von großer Bedeutung. Über die im vorherigen Kapitel beschriebenen Kriterien für die Partitionierung hinaus gibt es einige Grundregeln zu beachten, die allerdings nur dann eine merkbare Auswirkung auf die Performance eines Webservers haben, wenn dieser unter sehr hoher Last läuft und das Dateisystem als Flaschenhals identifiziert ist. Einen Webserver, der unter hoher Last läuft, weil die Programmierung der Webapplikation so viel Rechenzeit benötigt, und der dabei nur sehr wenig Festplatten-I/O hat, werden Sie durch eine andere Partitionierung oder ein anderes
168
Apache
Dateisystem nicht leistungsfähiger machen können. Daher gilt insbesondere für nachträgliche Tuningmaßnahmen: Identifizieren Sie zuerst den Flaschenhals, bevor Sie an der falschen Stelle arbeiten. Bei Datei- und Datenbankservern kann die Wahl eines optimierten Dateisystems merkbare Auswirkungen auf die Performance des Systems haben. Bei einem Webserver spielt das Dateisystem selbst eine eher untergeordnete Rolle, so dass Sie mit ext3 grundsätzlich gut beraten sind. Bei hohem Festplatten-I/O ist es sinnvoll, das DocumentRoot auf eine eigene Partition, besser noch auf eine eigene Festplatte zu legen. Der Speicherort des Webservers selbst ist unerheblich, da die Programmdatei nur beim Start des Servers von der Festplatte gelesen werden muss. Ein wichtiger Punkt ist allerdings, die Logdateien auf eine vom DocumentRoot getrennte Partition bzw. Festplatte zu legen. Durch betriebssysteminternes Caching wird zwar nicht für jeden Zugriff einzeln schreibend auf die Logdateien zugegriffen, allerdings vermerkt der Apache – wenn nicht anders konfiguriert – jeden Zugriff in seinen Logdateien, was bei vielen Zugriffen zu entsprechend vielen Festplattenzugriffen führt. Wenn die Festplattenzugriffe auf das DocumentRoot von denen auf die Logdateien entkoppelt sind, schafft das eine erhebliche Entlastung und Steigerung des Datendurchsatzes. Wenn keine zweite Partition oder Festplatte für die Logdateien zur Verfügung steht, sollte das Logging so spartanisch wie möglich ausfallen. Über die Direktive CustomLog können Sie das Format der Logeinträge selbst festlegen, so dass Sie unnötige Informationen ausfiltern können, bevor sie überhaupt auf die Platte geschrieben werden. Beim Ausliefern hauptsächlich statischer Inhalte können die Module mod_cache und mod_file_cache zu einer Verringerung des Festplatten-I/O beitragen. mod_ cache speichert ausgelieferte Dateien im Speicher und liefert diese bei erneuten Anfragen direkt aus, ohne die Dateien wieder von der Festplatte lesen zu müssen. Dabei bietet das Modul umfangreiche Konfigurations- und Optimierungsmöglichkeiten. mod_file_cache bietet eine ähnliche Funktionalität, ist aber wesentlich weniger komplex. So cached mod_file_cache Dateien während der gesamten Lebensdauer des Apache. Sobald sich eine Datei auf dem Datenträger ändert, muss der Apache neu gestartet werden. Für Websites mit ausschließlich statischen und sich selten verändernden Inhalten ist das eine durchaus sinnvolle Lösung.
169
4.1
4
Serverdienste
Cache oder nicht Cache … … das ist hier die Frage. Geschicktes Caching kann den Festplatten-I/O erheblich verringern. Die Krux liegt aber zum einen darin, dass sich Caching nur für statische Inhalte eignet, und zum anderen in der komplexen Konfiguration des Moduls mod_cache. Darüber hinaus erkauft man sich den geringeren Festplatten-I/O mit einem höheren Speicherverbrauch, denn die Inhalte, die sich im Cache befinden, werden im Hauptspeicher abgelegt. Ob Caching sinnvoll ist, hängt daher unmittelbar von der Struktur der auszuliefernden Daten und dem verfügbaren Hauptspeicher ab. Ist dieser aufgrund hoher Last bereits knapp, wird Caching keine Abhilfe schaffen, sondern den Server noch viel schneller zum Swappen treiben. Daher gilt auch hier: Holzauge sei wachsam!
DNS-Zugriffe Die in Abschnitt 4.1.2 bereits erwähnte Direktive HostnameLookups hat fatale Auswirkungen auf die Performance des Webservers, da dieser für jeden Request von einem Client einen Reverse-Lookup für die IP-Adresse des Clients durchführt. Schlimmer wird es noch, wenn HostnameLookups in Verbindung mit allow from domain oder deny from domain verwendet werden. Dann führt der Apache für jede Client-Anfrage zwei DNS-Abfragen durch. Die erste ist ein ReverseLookup der IP-Adresse des Clients und die zweite ein direkter Lookup, um das Ergebnis des Reverse-Lookups zu verifizieren. Gut gemeinter Tipp: Lassen Sie die Finger von HostnameLookups. Sendfile Moderne Linux-Systeme bieten den Systemaufruf sendfile (siehe hierzu man 2 sendfile). Dieser Systemaufruf ermöglicht einen schnellen Datenaustausch zwi-
schen zwei Dateideskriptoren. Der Apache verwendet ihn ab Version 2.0 standardmäßig. Der Einsatz von sendfile kann mit der Direktive EnableSendfile deaktiviert werden, allerdings sollte dies nur in Ausnahmesituationen geschehen, z. B. wenn das DocumentRoot auf einer Netzwerkfreigabe liegt. AllowOverride Wie in Abschnitt 4.1.2 beschrieben, hat die Verwendung dezentraler Konfigurationsdateien, der .htaccess-Dateien, einen negativen Einfluss auf die Performance des Webservers. Ist die Verwendung von .htaccess-Dateien durch das Setzen der Direktive AllowOverride erlaubt, versucht der Apache bei jedem Request die Datei .htaccess auf der höchsten Ebene des DocumentRoots und im aktuellen Verzeichnis zu öffnen, auch wenn sie gar nicht vorhanden ist. Mit strace lässt sich das sehr schön überprüfen. strace ist ein Programm, das die Systemaufrufe von Prozessen ausgibt, was für Analysezwecke sehr hilfreich ist.
170
Apache
Die nachfolgende Ausgabe von strace zeigt den Abruf der Indexseite vom Apache unter Ubuntu. Die Direktive AllowOverride AuthConfig ist aktiviert. # strace -f -o strace.out /etc/init.d/apache2 start [...] 5349 read(8, "GET / HTTP/1.1\r\nHost: hardy\r\nUse"..., 8000) = 439 5349 gettimeofday({1214132259, 72292}, NULL) = 0 5349 gettimeofday({1214132259, 72615}, NULL) = 0 5349 gettimeofday({1214132259, 72733}, NULL) = 0 5349 stat64("/var/www/", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 5349 open("/.htaccess", O_RDONLY|O_ LARGEFILE) = -1 ENOENT (No such file or directory) 5349 open("/var/.htaccess", O_RDONLY|O_ LARGEFILE) = -1 ENOENT (No such file or directory) 5349 open("/var/www/.htaccess", O_RDONLY|O_ LARGEFILE) = -1 ENOENT (No such file or directory) 5349 stat64("/var/www/ index.html", 0xbf98998c) = -1 ENOENT (No such file or directory) 5349 lstat64("/var", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 5349 lstat64("/var/www", {st_mode=S_IFDIR|0755, st_ size=4096, ...}) = 0 5349 lstat64("/var/www/ index.html", 0xbf98998c) = -1 ENOENT (No such file or directory) 5349 open("/var/www/", O_RDONLY|O_NONBLOCK|O_LARGEFILE|O_ DIRECTORY|0x80000) = 9 5349 fstat64(9, {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 5349 getdents(9, /* 2 entries */, 4096) = 32 5349 getdents(9, /* 0 entries */, 4096) = 0 5349 close(9) [...]
Nachdem der Apache den Request vom Client erhalten hat (GET / HTTP/1.1\r\ nHost: hardy\r\n), sucht er die .htaccess-Datei in den folgenden Verzeichnissen: /.htaccess /var/.htaccess /var/www/.htaccess
Dann erst liefert er die angefragte Datei aus. Durch das unbedarfte Aktivieren von AllowOverride hat sich die Anzahl der Dateisystemzugriffe pro Request vervierfacht! Neben den in Abschnitt 4.1.2 genannten Problemen mit der fehlenden Übersichtlichkeit durch die Verwendung von .htaccess-Dateien sollten Sie bei stark frequentierten Servern immer die zusätzliche Belastung durch die Dateisys-
171
4.1
4
Serverdienste
tem-Zugriffe im Hinterkopf behalten, wenn Sie mit dem Gedanken spielen, dezentrale Konfigurationsdateien zu erlauben. An dieser Stelle sei auch noch auf die Verwendung von Symlinks verwiesen, die ebenfalls zu erhöhtem Filesystem-I/O führt. Siehe hierzu den Abschnitt »Virtuelle Hosts« auf Seite 123. Prozesse Die Direktiven MinSpareServers, MaxSpareServers und StartServers sind im Zusammenhang mit dem Tuning des Apache ebenfalls von großer Bedeutung. Ideale Werte für diese Direktiven sind unmittelbar von den konkreten Gegebenheiten abhängig. Auf einem stark beschäftigten Server kann ein relativ hoher Wert von MinSpareServers zu einer spürbaren Performance-Verbesserung führen, insbesondere wenn der Server eine hohe Anzahl von Visits bearbeitet, d. h. viele Besucher bedient. Eine hohe Zahl von MinSpareServers stellt dann sicher, dass für einen neuen Besucher nicht erst ein neuer Prozess erzeugt werden muss, sondern dass dieser Benutzer direkt eine Antwort auf seine Anfrage erhält. Page Impressions und Visits Im Bereich der Webserver sind zwei Begriffe wichtig: Page Impressions und Visits. Page Impressions bezeichnen die Seitenabrufe, die ein Webserver beantwortet, Visits bezeichnet die Besucher einer Website. Ein Visit umfasst normalerweise mehrere Page Impressions, da ein Besucher selten nur eine Seite abruft und da der Abruf einer Webseite in der Regel weitere Requests für eingebettete Objekte, wie z. B. Grafiken, verursacht. Für den Serverbetreiber ist es wichtig zu wissen, in welchem Verhältnis Visits und Page Impressions zueinander stehen, da nur dann eine optimale Konfiguration des Servers möglich ist.
Da untätige Prozesse Speicherplatz verbrauchen, den die aktiven Prozesse viel besser gebrauchen können, muss mit MaxSpareServers eine Obergrenze für wartende Prozesse konfiguriert werden. Bei einer hohen Anzahl von Visits kann die Zahl der wartenden Prozesse etwas höher ausfallen, da davon auszugehen ist, dass häufig neue Benutzer Anfragen stellen und damit neue Prozesse verwenden. Liegt die Anzahl der Visits relativ niedrig, die Zahl der Page Impressions dafür aber höher, dann bedeutet dies, dass nur wenige Benutzer viele Anfragen stellen. Da nicht für jede Anfrage eines Benutzers ein neuer Prozess erzeugt wird, sondern ein Prozess die mit MaxRequestPerChild festgelegte Anzahl von Requests beantwortet, kann die Anzahl der wartenden Prozesse niedrig gehalten werden. Einen idealen Wert zu finden kann mühsam sein, es lohnt sich aber spätestens dann, wenn Sie jedes Quäntchen Leistung aus dem Webserver kitzeln müssen.
172
Apache
Von großer Bedeutung ist im Zusammenhang mit den Prozessen die Direktive KeepAliveTimeout, mit der die Zeit festgelegt wird, die ein Prozess innerhalb einer bereits bestehenden Verbindung auf eine weitere Anfrage wartet, bevor er die Verbindung beendet. Da HTTP 1.1 heutzutage Standard ist und Clients nicht für jede Anfrage eine neue TCP-Verbindung aufbauen, hängt ein optimaler KeepAliveTimeout-Wert unmittelbar mit der Erzeugung und dem Zerstören von Prozessen zusammen. Eine zu lange KeepAliveTimeout-Zeit führt dazu, dass Prozesse unnötig lange auf weitere Anfragen warten. Das Ergebnis sind untätige Prozesse, die keine Anfragen neuer Benutzer beantworten und unnötig Speicherplatz belegen. Eine zu kurze KeepAliveTimeout-Zeit beendet Prozesse zu früh und führt dazu, dass der Apache neue Prozesse für eigentlich bereits bestehende Verbindungen erzeugen muss. Dies kostet Performance in Form von Zeit und Rechenleistung. RLimit Für die Kontrolle externer, vom Apache aufgerufener Prozesse wie z. B. CGISkripte stehen die Direktiven RLimitCPU, RLimitMEM und RLimitNPROC zur Verfügung. RLimitCPU begrenzt die CPU-Zeit, die ein externer Prozess verwenden darf, RLimitMEM begrenzt den Speicher für einen externen Prozess und RLimitNPROC die Anzahl der von einem externen Prozess erzeugbaren Prozesse. Damit können Sie die Nachteile von CGI-Skripten nicht ausgleichen, Sie können lediglich Schadensbegrenzung betreiben. An der Warnung, wenn möglich auf CGI-Skripte zu verzichten, ändern auch diese Direktiven nichts.
4.1.8
Härtung
Ein Webserver ist ein per definitionem für die Öffentlichkeit zugänglicher Service, der daher eine besondere Beachtung bei der Systemhärtung finden muss. Ein Betriebssystem lässt sich relativ leicht härten. Durch das Deinstallieren nicht benötigter Pakete, das Festlegen restriktiver Berechtigungen und das Abschirmen nicht benötigter Ports durch eine Firewall lässt sich ein System bereits mit wenig Aufwand effizient sichern. Der Apache-Webserver ist ein Produkt mit einer langen Tradition – gemessen an den Entwicklungszyklen im Internet – und weist von Version zu Version immer weniger bekannte, kritische Sicherheitslücken auf. Nichtsdestotrotz sollten Sie einen aus dem Internet erreichbaren Dienst unbedingt über entsprechende Härtungsmaßnahmen sichern.
173
4.1
4
Serverdienste
Schlanke Konfiguration Die erste und wirkungsvollste Härtungsmaßnahme ist eine schlanke Konfiguration. Entfernen Sie alle Direktiven, die Sie nicht benötigen, insbesondere alle LoadModule-Direktiven, mit denen nicht benötigte Module geladen werden. Jedes geladene Modul vergrößert den Funktionsumfang des Apache-Webservers und erhöht damit das Risiko einer Sicherheitslücke. Unter Ubuntu müssen Sie dazu die entsprechenden symbolischen Links im Verzeichnis /etc/apache2/modsenabled entfernen. Das können Sie über das Programm a2dismod tun, das Ihnen auch direkt eine Liste der aktivierten Module anzeigt. Ein typischer Vertreter von auf einem Livesystem nicht benötigten Modulen ist beispielsweise mod_status. Nach dem Ändern der Konfiguration muss der Apache neu gestartet werden. # sudo a2dismod Which module would you like to disable? Your choices are: alias auth_basic authn_file authz_default authz_ groupfile authz_host authz_ user autoindex cgi dir env mime negotiation php5 setenvif ssl status Module name? status Module status disabled; run /etc/init.d/apache2 forcereload to fully disable.
HTTP-Methoden beschränken Das HTTP-Protokoll umfasst eine Reihe von Befehlen, die auf einem produktiven Webserver in der Regel nicht benötigt werden. Die Methode PUT z. B. benötigen Sie nur, wenn Sie über WebDAV Daten auf Ihrem Server ablegen möchten. Für eine »normale« Website benötigt der Webserver lediglich die Methoden GET und POST. Über die Direktive LimitExcept können Sie dem Apache mitteilen, dass er nur diese beiden Methoden akzeptieren soll: Deny from all
Eine Ausnahme hierbei sind die Methoden HEAD und TRACE, die von dieser Direktive nicht ausgeschlossen werden. Die Methode TRACE ist eine Methode, die nur zu Debugzwecken verwendet wird und für Cross-Site-Tracing-Angriffe (XST) missbraucht werden kann. Daher sollten Sie diese Methode immer deaktivieren. Dies ist mit der Direktive TraceEnable möglich: TraceEnable
off
Die HEAD-Methode ist ungefährlich und kann zu Monitoring- oder Analysezwecken verwendet werden, weswegen sie ohne Bedenken aktiviert bleiben kann.
174
Apache
Requestgröße begrenzen Automatische Angriffstools und Fuzzer manipulieren häufig Protokollwerte, um den Webserver zu einem Fehlverhalten zu provozieren. Über die vier Limit-Direktiven können Sie maximale Werte für HTTP-Anfragen definieren. Anfragen, die diese Werte übersteigen, werden vom Server verworfen. Zur Verfügung stehen die vier folgenden Direktiven: 왘
LimitRequestBody: Legt die maximale Größe der Request-Daten (ohne Hea-
der) in Byte fest. 왘
LimitRequestFields: Legt die maximale Anzahl von Header-Feldern in einem
Request fest. 왘
LimitRequestFieldSize: Legt die maximale Größe der Header-Felder fest.
왘
LimitRequestLine: Legt die maximale Anzahl von Zeilen pro Request fest.
Fehlerausgaben Ein Angreifer lernt anhand von Fehlermeldungen am schnellsten Details über das Zielsystem. Das erste Ziel eines Angreifers ist es daher, durch Fehleingaben oder Fehlbedienung den Webserver oder die Webapplikation zur Ausgabe von Fehlermeldungen zu provozieren. Fehlermeldungen können sensible Daten enthalten, z. B. interne IP-Adressen, Pfade, Dateinamen, Benutzernamen, Passwörter etc. Darüber hinaus sind automatisierte Angriffe immer dann besonders effizient, wenn ein Webserver für verschiedene Fehlerzustände verschiedene Fehlermeldungen ausgibt. Ein Scantool wie Nikto8 entscheidet anhand verschiedener Fehlermeldungen des Webservers, ob eine abgerufene Datei oder ein Verzeichnis vorhanden ist oder nicht. Der erste Schritt für einen Administrator sollte daher sein, den Apache so zu konfigurieren, dass er für jeden Fehlerzustand dieselbe neutrale Fehlerseite anzeigt. Definieren Sie dazu für jeden serverseitigen Fehler eine Umleitung auf dieselbe Fehlerseite. Diese Umleitung können Sie mit der Direktive ErrorDocument definieren: ErrorDocument ErrorDocument ErrorDocument ErrorDocument
Die Zahlen hinter dem Direktiven-Namen geben den HTTP-Fehlercode an, für den die Direktive gilt. Die Datei am Ende der Zeile ist die Fehlerseite, die der Apache beim Eintritt des betreffenden Fehlers ausgibt. Wenn Sie unterschiedliche
8 http://www.cirt.net/nikto2
175
4.1
4
Serverdienste
Fehlerseiten für die Fehler »Not found« (404) »Access denied« (403) definieren, kann ein Angreifer auf diese Weise Datei- und Verzeichnisnamen auf Ihrem Server enumerieren. Standarddateien und -verzeichnisse Der Apache bringt in der Standardinstallation einige Dateien und Verzeichnisse mit, die für den Livebetrieb nicht benötigt werden, dem Angreifer aber einen Hinweis darauf geben können, dass der Server nicht gehärtet worden ist – eben weil diese Dateien und Verzeichnisse noch vorhanden sind. Das sind insbesondere die Verzeichnisse icons, manual und cgi-bin mit den darin enthaltenen Dateien. Löschen Sie diese Verzeichnisse samt der enthaltenen Dateien, oder entfernen Sie alle Direktiven, die den Zugriff auf diese Verzeichnisse und Dateien ermöglichen.
4.2
Datenbanken
Dynamische Webauftritte sind ohne Datenbanken nicht denkbar. Als das WWW seinen Kinderschuhen entstiegen war und dynamische Webauftritte populär wurden, erlebte das Softwareprodukt Datenbank, das bis dato hauptsächlich auf Großrechnern in dunklen Kellern großer Firmen zu finden war, einen ungeheuren Popularitätsschub.
4.2.1
MySQL
MySQL ist ein quelloffenes relationales Datenbankmanagementsystem (DBMS), das für den nicht-kommerziellen Gebrauch unter der GPL verfügbar, für kommerziellen Einsatz jedoch kostenpflichtig ist. Seit Februar 2008 gehört MySQL der Firma Sun Microsystems. MySQL ist ungefähr zur gleichen Zeit für PHP entwickelt worden und zeichnete sich schon von Anfang an durch ein leicht zu durchschauendes Berechtigungsmodell, eine einfache Installation und hohe Performance aus. Dies mag der Grund dafür gewesen sein, dass MySQL zusammen mit PHP, das ungefähr zur selben Zeit erschienen ist, und dem Apache-Webserver zu dem typischen Gespann für dynamische Webauftritte wurde, dem so genannten LAMP-System. LAMP steht für die Anfangsbuchstaben der Wörter Linux, Apache, MySQL und PHP. In den Anfangszeiten war die Funktionalität von MySQL recht bescheiden. So gab es bis zur Version 3.23 keine Transaktionen, und die ersten verfügbaren Versionen von MySQL boten noch nicht einmal referenzielle Integrität der Daten.
176
Datenbanken
Stored Procedures, in anderen DBMS schon lange Standard, hielten sogar erst mit der Version 5 Einzug in MySQL. Dies hat dem Erfolg von MySQL im Web keinen Abbruch getan, denn Transaktionen und referenzielle Integrität waren damals, Ende der 90er Jahre, in der Dinosaurierzeit des WWW, nicht gefragt. Für professionelle Anwendungen wurde Oracle benutzt, aber für die unzähligen dynamischen Webauftritte, die lediglich ein DBMS zur Ablage von Daten benötigten, war MySQL absolut ausreichend. Und auch heute ist MySQL häufig das erste Mittel der Wahl, wenn es um einen dynamischen Webauftritt auf PHP-Basis geht. Die Schnittstelle zwischen PHP und MySQL ist seit jeher sehr gut gewesen, so dass der Zugriff auf eine MySQL-Datenbank über PHP ohne Probleme und großen Aufwand realisiert werden kann. Installation und Konfiguration Unter Ubuntu ist die Installation von MySQL wie immer ganz einfach: # sudo apt-get install mysql-server
Während der Installation werden Sie nach dem zu vergebenden Root-Passwort für den MySQL-Server gefragt. Seien Sie nicht faul, und vergeben Sie ein Passwort. Die schönste Systemhärtung eines Webservers inklusiver ausgefeilter Konfiguration von Suhosin nutzt nichts, wenn man ohne Passwort auf den Datenbankserver zugreifen kann. Da die Bedienung von MySQL über die Kommandozeile eher mühsam ist, sollten Sie in einem zweiten Schritt noch das Programm phpMyAdmin installieren. Dabei handelt es sich um eine Webapplikation auf PHP-Basis, mit der Sie den MySQLServer komplett administrieren können. phpMyAdmin ist Ende der 90er Jahre entstanden und hat sich seitdem zum Quasi-Standard für die Administration von MySQL entwickelt. Selbst große Webhoster bieten ihren Kunden phpMyAdmin zur Administration ihrer Datenbanken an. phpMyAdmin steht den Konfigurationstools »großer« Datenbanksysteme in nichts nach und bietet alle Funktionen, die zur Administration des Datenbankservers notwendig sind. Die Installation von phpMyAdmin ist ebenso einfach wie die von MySQL: # sudo apt-get install phpmyadmin
Sie werden nach dem Root-Passwort für die Datenbank gefragt, da phpMyAdmin dieses für den Zugriff benötigt. Darüber hinaus fragt der Installer noch, welcher Webserver verwendet werden soll. Wählen Sie hier Apache 2 aus.
177
4.2
4
Serverdienste
Der Installer legt im Verzeichnis /etc/apache2/conf.d einen symbolischen Link auf die Daten /etc/phpmyadmin/apache.conf an. Damit ist die Konfiguration des Apache-Servers für die Verwendung von phpMyAdmin abgeschlossen. Die Konfigurationsdatei enthält einige Direktiven für das phpMyAdmin-Verzeichnis und erzeugt einen Alias phpmyadmin, so dass Sie die Administrationsoberfläche nach einem Neustart des Apache im Verzeichnis /phpmyadmin finden können (siehe Abbildung 4.20). Die Tatsache, dass phpMyAdmin funktioniert, ist der Beweis dafür, dass die Installation des LAMP-Systems erfolgreich war. Der Apache ist erreichbar, PHP läuft und kann auf MySQL zugreifen. Voilà!
Abbildung 4.20 phpMyAdmin out-of-the-Box unter Ubuntu
Unter Gentoo ist die Installation ähnlich einfach: emerge mysql
Nach Abschluss der Installation, die einige Zeit dauern kann, da MySQL recht umfangreich ist und das Kompilieren entsprechend lange dauert, können Sie das installierte Paket konfigurieren, d. h. insbesondere ein Root-Passwort vergeben:
178
Datenbanken
# emerge --config =dev-db/mysql-5.0.54 Configuring pkg... * Creating the mysql database and setting proper * permissions on it ... * Insert a password for the mysql 'root' user * Avoid ["'\_%] characters in the password > * Retype the password > * Loading "zoneinfo", this step may require a few seconds ... * Stopping the server ... * Done
Damit der MySQL-Server beim Systemstart automatisch gestartet wird, verwenden Sie rc-update, um den Dienst entsprechend zu konfigurieren: # sudo rc-update add mysql default * mysql added to runlevel default
Die Installation von phpMyAdmin ist vordergründig einfach: emerge phpmyadmin
Allerdings wird sie, sofern Sie die Standard-USE-Flags verwenden, mit einem Fehler terminieren: * dev-lang/php-5.2.6_rc4 needs to be re-installed with all of the following * USE flags enabled: * * ctype pcre session unicode * * as well as any of the following USE flags enabled: * * mysql or mysqli if using dev-lang/php-5 * mysql if using dev-lang/php-4
Also müssen Sie die USE-Flags entsprechend setzen (/etc/make.conf oder Umgebungsvariable) und sowohl PHP als auch MySQL erneut installieren. Anschließend können Sie phpMyAdmin erneut installieren. Nach Abschluss der Installation sind noch einige Dinge zu erledigen, worauf die Installation aufmerksam macht: If this is a new installation: 1. Configure phpmyadmin: a) Create config.inc.php. You can use the web-based installer: mkdir /var/www/localhost/htdocs/phpmyadmin/config
179
4.2
4
Serverdienste
chown apache:apache /var/www/localhost/htdocs/phpmyadmin/config then go to http://localhost//phpmyadmin/scripts/setup.php once you've saved the configuration: cp /var/www/localhost/htdocs/phpmyadmin/config/config.inc.php / var/www/localhost/htdocs/phpmyadmin/config.inc.php rm -rf /var/www/localhost/htdocs/phpmyadmin/config b) Alternatively, use an existing configuration: cp <path to existing config.inc.php file> /var/www/localhost/ htdocs/phpmyadmin/ c) Alternatively, use the sample config file: cp /var/www/localhost/htdocs/phpmyadmin/config.sample.inc.php / var/www/localhost/htdocs/phpmyadmin/config.inc.php 2. Be sure that the libraries/ directory is not visible. You can use the provided .htaccess file.
Da noch keine Konfiguration vorhanden ist, wenden Sie Vorschlag a) an und führen die dort angegebenen Befehle aus. Beim Aufruf der URL http://localhost/ phpmyadmin/scripts/setup.php weist phpMyAdmin darauf hin, dass die Verbindung unverschlüsselt ist. Da der Apache aber mit SSL ausgestattet ist, können Sie auch über eine verschlüsselte Verbindung arbeiten. Rufen Sie dazu einfach dieselbe URL mit dem Präfix https auf: https://localhost/phpmyadmin/scripts/setup.php Anmerkungen zur URL Beim Aufruf der URL müssen Sie den Hostnamen localhost durch den Namen Ihres Servers ersetzen. Warum in der Ausgabe von emerge nach localhost ein Doppelslash steht, bleibt allerdings das Geheimnis der Paket-Maintainer.
Auf der Startseite des Setup-Skriptes wählen Sie in der Zeile Add, um einen neuen Server anzulegen. Im darauffolgenden Dialog (siehe Abbildung 4.21) tragen Sie unter Server hostname den kanonischen Namen des Servers ein, auf dem phpMyAdmin läuft. Als Connection type wählen Sie socket aus, und im Feld Password for config auth tragen Sie das Passwort des root-Benutzers des MySQL-Servers ein. Über den Button Add unter den Formularfeldern fügen Sie den Server zur Liste der konfigurierten Server hinzu.
180
Datenbanken
Abbildung 4.21
Konfiguration des MySQL-Servers in phpMyAdmin
Sie kommen damit auf die Übersichtsseite des Konfigurationsskriptes zurück, wo Sie in der Zeile Configuration auf den Button Save klicken, um die Konfiguration in eine Datei schreiben zu lassen (siehe Abbildung 4.22).
181
4.2
4
Serverdienste
Abbildung 4.22
Schreiben der Konfiguration
Das Konfigurationsskript gibt die folgende Meldung aus: Configuration saved to file config/ config.inc.php in phpMyAdmin top level directory, copy it to top lev el one and delete directory config to use it.
Dieser Anweisung folgen Sie und kopieren die Datei /var/www/localhost/htdocs/ phpmyadmin/config/config.inc.php in das übergeordnete Verzeichnis /var/www/ localhost/htdocs/phpmyadmin/. Nach dieser Operation funktioniert phpMyAdmin auch unter Gentoo (siehe Abbildung 4.23).
182
Datenbanken
Abbildung 4.23 phpMyAdmin unter Gentoo
Zum Abschluss der Konfiguration ist noch Punkt 2 der Anweisungen des Installers zu folgen: 2. Be sure that the libraries/ directory is not visible. You can use the provided .htaccess file.
Falls Sie ohnehin .htaccess-Dateien verwenden, können Sie dies tatsächlich über .htaccess-Dateien bewerkstelligen, ansonsten sperren Sie den Zugriff einfach über eine Directory-Direktive in der zentralen Konfigurationsdatei: AllowOverride None Options none Order allow,deny Allow from localhost
183
4.2
4
Serverdienste
Benutzerverwaltung Die Benutzerverwaltung von MySQL ist recht einfach. Es hält sich hartnäckig das Gerücht, dass dem nicht so sei, aber dieses Gerücht stammt noch aus den Zeiten, als MySQL nur über die Kommandozeile zu administrieren war (die Prä-phpMyAdmin-Ära). Mit phpMyAdmin ist die Benutzerverwaltung allerdings harmlos. Auf der Oberfläche von phpMyAdmin verbirgt sich die Benutzerverwaltung hinter dem Punkt Rechte (siehe Abbildung 4.24).
Abbildung 4.24 Benutzerverwaltung mit phpMyAdmin
Am einfachsten lässt sich die Vergabe von Rechten beim Einrichten einer neuen Datenbank demonstrieren. Gehen Sie dazu auf die Startseite von phpMyAdmin, und legen Sie im Textfeld Neue Datenbank anlegen die Datenbank »foo« an, der Sie im Textfeld Zeichensatz / Kollation der MySQL-Verbindung den Zeichensatz utf8_unicode_ci zuweisen. (siehe Abbildung 4.25). Im nächsten Dialog legen Sie in der neu erzeugten Datenbank eine Tabelle »bar« an und verpassen dieser zwei Felder (siehe Abbildung 4.26). Der folgende Dialog fragt Namen und Typ der Felder und die zu verwendende Storage Engine ab. Nennen Sie das erste Feld »ID«, und geben Sie ihm den Typ INT, das zweite Feld nennen Sie »Text« und
184
Datenbanken
geben ihm den Typ VARCHAR mit der Länge »50«. Das Tabellenformat – die Storage Engine – lassen Sie auf MyISAM (siehe Abbildung 4.27). Zum Fertigstellen klicken Sie auf den Button Speichern.
Abbildung 4.25 Eine neue Datenbank
Abbildung 4.26
Eine neue Tabelle
185
4.2
4
Serverdienste
Abbildung 4.27
Die Felder der Tabelle
phpMyAdmin zeigt grundsätzlich die an die Datenbank abgesetzten SQL-Statements an, so auch nach dem Erzeugen einer neuen Tabelle: CREATE TABLE `foo`.`bar` ( `ID` INT NOT NULL , `Text` VARCHAR( 50 ) NOT NULL ) ENGINE = MYISAM
SQL für echte Männer Dieses SQL-Statement können Sie auch per Kommandozeile an MySQL übergeben. Das kann hilfreich sein, wenn Sie auf einem Testsystem phpMyAdmin zur Verfügung haben, auf dem Produktivsystem jedoch nicht. Machen Sie sich nicht die Arbeit, alle SQL-Statements zu Fuß zu erstellen, sondern führen Sie alle relevanten Schritte mit phpMyAdmin auf dem Testsystem durch, speichern Sie die SQL-Statements in einer Textdatei, und übergeben Sie dann auf dem Produktivsystem diese Textdatei an MySQL. Sie können auch die gesamte Datenbank vom Testsystem in eine Textdatei dumpen und diesen Dump auf dem Produktivsystem wieder einlesen, aber bekanntlich führen ja viele Wege nach Rom.
Als Nächstes erstellen Sie einen Datenbankbenutzer, der Zugriff auf die neuangelegte Datenbank »foo« erhält. Dazu wählen Sie auf der Startseite von phpMyAdmin den Punkt Rechte aus und klicken auf der dann erscheinenden Seite auf die Schaltfläche Neuen Benutzer hinzufügen (Abbildung 4.28).
186
Datenbanken
Abbildung 4.28
Die Benutzerverwaltung von phpMyAdmin
Im folgenden Dialog geben Sie dem Benutzer einen Namen und wählen im Dropdown-Feld Host den Wert lokal aus. Damit legen Sie fest, dass der Benutzer nur vom lokalen Host aus auf die MySQL-Datenbank zugreifen darf. Das erscheint auf den ersten Blick widersinnig, ist aber leicht erklärt. Der Benutzer soll von einer Webapplikation für den Datenbankzugriff verwendet werden. Webserver und Datenbankserver laufen auf derselben Maschine, so dass der Zugriff von der Webapplikation auf die Datenbank nicht von extern kommt, sondern nur von der lokalen Maschine. Sobald Webserver und Datenbankserver auf getrennten Maschinen laufen, müssen Sie die Rechte des Benutzers entsprechend anpassen. Mögliche Werte für das Host-Feld wären dann das Prozentzeichen (%) für »alle Hosts« (schlecht) oder die IP-Adresse des Webservers (gut). Auch hier empfiehlt es sich, die Rechte so restriktiv wie möglich zu vergeben, um zu verhindern, dass mit dem Datenbankbenutzer von anderen Systemen als den vorgesehenen auf die Datenbank zugegriffen werden kann.
187
4.2
4
Serverdienste
Benutzer und Hosts MySQL unterscheidet Benutzer nicht allein anhand des Namens, sondern an der Kombination aus Namen und Host. Dadurch ist es möglich, einen einzigen Benutzernamen mehrmals anzulegen, mit jeweils verschiedenen Rechten für unterschiedliche Hosts.
Durch Fehler in einer Webapplikation kann es vorkommen, dass interne Daten preisgegeben werden, z. B. Datenbankbenutzer und das Passwort dieses Benutzers. Wenn der Benutzer dann weitreichende Rechte hat und von überall her auf die Datenbank zugreifen kann, ist einem Angreifer der Zugriff auf die Datenbank ohne Probleme möglich. Darf der betroffene Datenbankbenutzer nur vom lokalen Host oder anderen, genau spezifizierten IP-Adressen auf die Datenbank zugreifen, macht das einem Angreifer das Leben schon schwerer. Zum Abschluss der Benutzerkonfiguration vergeben Sie für den Benutzer noch ein Passwort, lassen alle Rechte auf der Seite deaktiviert und erzeugen den Benutzer durch Betätigen des OK-Buttons (Abbildung 4.29).
Abbildung 4.29
188
Die Rechte des Benutzers
Datenbanken
Für die Akten: phpMyAdmin gibt auch hier das SQL-Statement zum Erzeugen des Benutzers aus. Es empfiehlt sich, dieses Statement immer noch einmal zu kontrollieren, denn wie jede Software kann auch phpMyAdmin Fehler enthalten und möglicherweise falsche Aktionen auf der Datenbank ausführen. CREATE USER 'john.doe'@'localhost' IDENTIFIED BY '********'; GRANT USAGE ON * . * TO 'john.doe'@'localhost' IDENTIFIED BY '********' WITH MAX_QUERIES_PER_HOUR 0 MAX_CONNECTIONS_PER_HOUR 0 MAX_UPDATES_ PER_HOUR 0 MAX_USER_CONNECTIONS 0 ;
Ressourcenbeschränkungen Die Konfiguration der globalen Rechte lässt auch die Regelung von Ressourcenbeschränkungen zu. Dazu existieren die Werte MAX_QUERIES_PER_HOUR (maximale Anzahl der Anfragen pro Stunde), MAX_UPDATES_PER_HOUR (maximale Anzahl von Updates pro Stunde), MAX_CONNECTIONS_PER_HOUR (maximale Anzahl neuer Datenbankverbindungen pro Stunde) und MAX_USER_CONNECTION (maximale Anzahl gleichzeitiger Datenbankverbindungen pro Stunde). Diese Werte können Sie pro Datenbankbenutzer vergeben.
Auch an dieser Stelle mag das Vorgehen widersinnig erscheinen, für den Benutzer keine Rechte zu vergeben. Allerdings kennt MySQL zwei Arten von Rechten, globale und datenbankbezogene. Die globalen Rechte gelten für alle Datenbanken, auf die ein Benutzer zugreifen kann, und die datenbankspezifischen Rechte nur für die Datenbanken, für die der Benutzer entsprechend eingerichtet ist. Beim Anlegen eines Benutzers lassen sich nur globale Rechte vergeben, was in diesem Fall aber nicht gewünscht ist, da der Benutzer so wenige Rechte wie möglich erhalten soll. Im nächsten Schritt werden Sie daher die datenbankspezifischen Rechte setzen, um dem Benutzer dadurch Zugriff auf die eben angelegte Datenbank zu ermöglichen. Die Möglichkeit dazu bietet die nach dem Anlegen des Benutzers erscheinende Bestätigungsseite im Bereich Datenbankspezifische Rechte. Dort wählen Sie die Datenbank aus, für die der Benutzer Rechte erhalten soll.
Abbildung 4.30
Datenbankspezifische Rechte für die Datenbank »foo«
189
4.2
4
Serverdienste
Anschließend können Sie dem Benutzer die Rechte für die ausgewählte Tabelle geben, die er benötigt. Für eine Webapplikation reichen meist die geringstmöglichen Rechte, d. h. SELECT, INSERT, UPDATE und DELETE. Damit kann der Benutzer alle Operationen mit den Daten in der Tabelle ausführen. Die Rechte im Bereich Struktur braucht ein Benutzer nur, wenn er seine Datenbank selbst administrieren können soll, also Tabellen löschen oder ändern etc. Die Rechte für die Administration, insbesondere GRANT, sollten ausschließlich Administratoren vorbehalten sein, da damit Benutzern Rechte vergeben werden können. Auch hier gilt: Gehen Sie so sparsam wie möglich mit den Rechten um, Webapplikationen stehen im Internet, und das Internet ist ein finsterer Ort.
Abbildung 4.31
Die Rechte des Benutzers für die Datenbank »foo«
Im unteren Teil der Seite gibt es den Bereich Tabellenspezifische Rechte, mit dem Sie die Rechte für den Benutzer noch weiter in Zugriffsrechte für Tabellen und Tabellenspalten granulieren können. Bestätigen Sie die Rechte des Benutzers mit dem OK-Button, und kontrollieren Sie das SQL-Statement, das phpMyAdmin ausgibt:
190
Datenbanken
GRANT SELECT , INSERT , UPDATE , DELETE ON `foo` . * TO 'john.doe'@' localhost';
Die Arbeit ist damit getan, Sie haben eine neue Datenbank angelegt und einen Datenbankbenutzer, der Zugriffsrechte auf diese Datenbank – und keine andere – hat. Kontrollieren können Sie die Zugriffsrechte des Benutzers in der Benutzerverwaltung von phpMyAdmin (Rechte) und in der Übersicht über die Datenbanken (siehe Abbildung 4.32).
Abbildung 4.32
Die Übersicht über die Datenbanken
Dort wählen Sie am rechten Rand das Icon neben der Datenbank, zu der Sie die Benutzerrechte sehen möchten. Im folgenden Dialog sehen Sie alle Benutzer, die Zugriff auf diese Datenbank haben (Abbildung 4.33).
Abbildung 4.33
Benutzer mit Rechten auf der Datenbank »foo«
Benutzerverwaltung anno dazumal MySQL speichert alle Berechtigungen in den Tabellen der Datenbank »mysql«. Die Tabelle »user« enthält die Benutzer der Datenbank mit ihren globalen Rechten, die Tabelle »db« die datenbankspezifischen Rechte etc. Den obenangelegten Benutzer können Sie samt seiner Rechte in diesen beiden Tabellen wiederfinden.
191
4.2
4
Serverdienste
In der Zeit vor Verfügbarkeit von Administrationswerkzeugen wie phpMyAdmin mussten Benutzer über die Kommandozeile durch Einträge in die einzelnen Datenbanken angelegt werden. Aus dieser Zeit stammt auch das Gerücht über die komplizierte Rechtestruktur von MySQL. phpMyAdmin fasst diese Einzelschritte zusammen und erleichtert dem Datenbankadministrator die Arbeit enorm.
Datenbanksicherheit Viel zu häufig machen sich Programmierer oder Datenbankadministratoren das Leben leicht und verwenden Benutzer mit zu umfangreichen Rechten oder gar Administrationsrechten für einfache Datenbankzugriffe. Damit kann ein kleines Problem wie eine SQL-Injection zu einem sehr großen werden, denn sobald der Datenbankbenutzer, den eine Webapplikation für den Zugriff verwendet, mehr Rechte hat als notwendig, kann ein Angreifer über eine SQL-Injection auch mehr Daten sehen bzw. mehr Schaden anrichten als notwendig. Eine erfolgreich ausnutzbare SQL-Injection erlaubt in 90 % der Fälle das Auslesen des kompletten Datenbestands einer Datenbank, wo bei korrekter Vergabe von Benutzerrechten eigentlich nur der Datenbestand der verwundbaren Webapplikation einsehbar sein dürfte. Sorgsamer Umgang mit Rechten hat daher insbesondere bei Datenbanken für Webapplikationen einen großen Einfluss auf die Schadenshöhe, die ein Angreifer verursachen kann. SQL-Injections können überall dort in Webapplikationen auftreten, wo Benutzereingaben ungefiltert an eine Datenbank weitergegeben werden. Ein Beispiel ist eine Login-Maske in einer PHP-Seite. Auf dieser Seite gibt es ein Textfeld für den Benutzernamen und eins für das Passwort. Die von einem Benutzer eingegebenen Daten werden direkt in eine SQL-Abfrage eingesetzt und diese Abfrage an die Datenbank abgesetzt, um den Benutzer zu authentifizieren. $query = „select * from users where user=’{$_POST[‘user’]}’ and pass=’{$_POST[‘pass’]}’”; {$_POST[‘user’]} und {$_POST[‘pass’]} sind dabei die Variablen, welche die
Inhalte der beiden Textfelder für den Benutzernamen und das Passwort enthalten. Da beide Variablen ohne Filterung in den Query-String eingesetzt werden, kann ein Angreifer durch Einfügen von Sonderzeichen diesen Query-String so manipulieren, dass die Datenbank die Abfrage nicht mehr versteht, was einen Fehler provoziert. Dafür reicht häufig schon ein einziges Hochkomma oder ein Semikolon aus. Angenommen, der Benutzername in diesem Beispiel ist »foo« und das Passwort »bar«, dann sieht der Query-String, der an die Datenbank geschickt wird, wie folgt aus: select * from users where user=’foo’ and pass=’bar’
192
Datenbanken
Die Überprüfung funktioniert in diesem Fall so, wie sie soll: Die Datenbank gibt nur dann einen Datensatz zurück, wenn ein gültiger Benutzername und das dazugehörige Passwort eingegeben wurden. Interessant wird es, wenn ein Angreifer in die Textfelder Sonderzeichen und SQL-Befehle eingibt. Diese baut das PHPSkript in den Query-String ein und übergibt diesen an die Datenbank. Fertig ist die SQL-Injection. Um beim Beispiel zu bleiben: Ein Angreifer gibt als Passwort die Zeichenkette pass’or’1’=’1 ein. Damit wird der Query-String zu folgender SQL-Anfrage: select * from users where user=’foo’ and pass=’bar’or’1’=’1 or ist ein SQL-Befehl, der in diesem Fall zur Folge hat, dass die Datenbank genau dann einen Wert zurückliefert, wenn Benutzername und Passwort korrekt sind, oder (dafür steht das or) wenn 1=1 ist. Man muss kein Mathematiker sein, um zu erkennen, dass die Bedingung 1=1 immer zutrifft. Ergo lässt sich mit diesem kleinen Fingertrick die komplette Authentifizierung umgehen, man spricht von einer SQL-Injection.
Das Umgehen von Authentifizierungsmechanismen via SQL-Injection ist nur ein Beispiel. Viel interessanter ist es, dass anstelle des simplen ’or’1’=’1 beliebige SQL-Befehle eingebaut werden können. Hier schließt sich der Kreis zu der im Abschnitt »Benutzerverwaltung« auf Seite 184 angemahnten Sparsamkeit bei der Vergabe von Rechten. Besitzt der Datenbankbenutzer, den die durch eine SQLInjection verwundbare Webapplikation verwendet, mehr Rechte, als er benötigt – möglicherweise sogar Administrationsrechte –, kann ein Angreifer über eine SQL-Injection nicht nur beliebige Daten aus der Datenbank auslesen, sondern auch Daten verändern, löschen etc. Besonders prekär an einer SQL-Injection ist, dass hier eine Sicherheitslücke einer Anwendung unmittelbar auf das Sicherheitskonzept des Servers trifft. Ein Administrator hat in der Regel wenig Einfluss auf Sicherheitslücken in einer Applikation, nichtsdestotrotz wird sein System davon aber in Mitleidenschaft gezogen werden, wenn ein Angreifer z. B. den kompletten Inhalt der Datenbank löscht. Daher sollte die Administration immer so sicher wie möglich erfolgen und die Vergabe von Rechten möglichst restriktiv sein. Kann ein Angreifer »nur« die Datenbank der betroffenen Webapplikation kompromittieren, ist das zwar ärgerlich, erzeugt aber keine Kollateralschäden. Optimierung Bei der Optimierung von DBMS gibt es zwei wichtige Themen: den Server und das Datenmodell bzw. die Programmierung. Die Optimierung des Datenmodells und der Programmierung sind nicht Gegenstand dieses Buches, wohl aber die
193
4.2
4
Serverdienste
Optimierung des Servers. Dies beginnt wieder ganz profan und knüpft an die im Abschnitt »Speicherverbrauch« auf Seite 163 gemachten Aussagen an. Die Performance eines Datenbankservers steht und fällt mit dem verfügbaren Hauptspeicher. Sobald das Betriebssystem anfängt, Speicher auf die Festplatte auszulagern, ist es vorbei mit der Performance. Darüber hinaus kommt bei Datenbanken mit großen Datenbeständen das Dateisystem als ein wichtiger Faktor ins Spiel. Die Datenverzeichnisse von solchen Datenbanken sollten möglichst auf eigene Festplatten ausgelagert werden, um einen optimalen Festplatten-I/O zu bekommen. Da die Daten in großen Dateien abgelegt sind, ist kein hochoptimiertes Dateisystem notwendig, vielmehr sollten Sie beim Anlegen des Dateisystems auf eine große Blockgröße achten. MySQL-Datendateien können schnell auf mehrere hundert Megabyte anwachsen, da helfen große Blöcke des Dateisystems den Datendurchsatz zu steigern. MySQL abstrahiert die Schnittstelle für die Verwaltung der Daten, so dass die Datenbankhaltung auf verschiedene Arten erfolgen kann. MySQL nennt diese Arten Storage Engines und bezeichnet damit unterschiedliche Technologien, die für unterschiedliche Einsatzbereiche gedacht sind. Die Standard-Storage-Engine ist MyISAM, eine Weiterentwicklung der ursprünglich von MySQL verwendeten ISAMEngine. MyISAM ist für den Einsatz im Web optimiert und bietet eine hohe Performance bei vielen gleichzeitigen Lesezugriffen. Dieser Vorteil wird durch das Fehlen von Transaktionen erkauft, die aber gerade im Webumfeld häufig nicht benötigt werden. Sofern Sie keine besonderen Anforderungen an Ihre Datenbank stellen, starten Sie mit MyISAM, es sei denn, die von Ihnen verwendete Webapplikation benötigt eine andere Storage Engine. Darüber hinaus bietet MyISAM den Vorteil, dass es Online-Backups unterstützt, was einen erheblichen Einfluss auf die Verfügbarkeit der Datenbank und damit auf die mit der Datenbank verbundenen Webapplikationen hat. Details hierzu enthält Abschnitt »Backup« auf Seite 200. Die Unterstützung von Transaktionen und damit Rollbacks bietet die Storage Engine InnoDB. Prüfen Sie vor dem Einsatz von InnoDB, ob Sie wirklich Transaktionen benötigen. Wenn ja, sollten Sie die Verwendung von PostgreSQL in Betracht ziehen, denn die Stärke von MySQL ist nach wie vor die hohe Performance im typischen Webbetrieb mit MyISAM, wohingegen PostgreSQL schon seit jeher als robuste Datenbank gilt, die für die Arbeit mit Transaktionen hervorragend geeignet ist (siehe hierzu Abschnitt 4.2.2). Ein wichtiger Unterschied zwischen MyISAM und InnoDB ist, dass MyISAM bei schreibenden Zugriffen die ganze betroffene Tabelle für Schreibzugriffe durch andere Prozesse sperrt, um die Integrität der Daten sicherzustellen. Dies ist im Webumfeld, wo häufig wesentlich mehr lesend als schreibend auf eine Daten-
194
Datenbanken
bank zugegriffen wird, ein akzeptables Vorgehen, zumal auch dadurch die hohe Performance der MyISAM-Engine erzielt wird. Eine tabellenweite Schreibsperre bedeutet, dass alle anderen Prozesse, die schreibend auf eine Tabelle zugreifen möchten, so lange warten müssen, bis die Schreibsperre auf diese Tabelle wieder aufgehoben ist. Für diesen Zweck pflegt MySQL eine Queue. InnoDB hingegen sperrt auf Datensatzebene, d. h., andere Prozesse, die in dieselbe Tabelle, aber in andere Datensätze schreiben möchten, können dies tun und müssen nicht warten, bis die Sperrung der ganzen Tabelle wieder aufgehoben ist, wie es bei MyISAM der Fall ist. Wenn Ihr spezifischer Anwendungsfall häufige Schreibzugriffe vorsieht, sollten Sie daher prüfen, ob InnoDB nicht die bessere Wahl ist. Eine allgemeingültige Formel, ab welcher Anzahl von Schreibzugriffen InnoDB gegenüber MyISAM die Nase vorn hat, gibt es nicht, hier läuft es im Einzelfall auf einen Vergleich hinaus. Herausfinden lässt sich der Status der Tabellensperre bei MyISAM-Tabellen durch einen Blick auf die beiden Variablen Table_locks_waited und Table_locks_immediate. Die erste Variable enthält die Anzahl der Schreibzugriffe, die während einer bestehenden Tabellensperre schreibend auf die gesperrte Tabelle zugreifen wollten und in die Queue eingereiht wurden. Die zweite Variable gibt die Anzahl der Schreibzugriffe an, die direkt, d. h. ohne Umweg über die Queue, erfolgt sind. Aus dem Verhältnis der beiden Werte zueinander lässt sich ermitteln, ob Tabellensperren ein Performanceproblem darstellen oder nicht. Die Werte der Variablen erhalten Sie über die Kommandozeile oder über phpMyAdmin. Beachten Sie, dass die Werte der Variablen nur für die Laufzeit des MySQL-Servers gültig sind. Bei einem Neustart des Server oder des gesamten Betriebssystems werden die Werte gelöscht. Um über die Kommandozeile mit der MySQL-Datenbank kommunizieren zu können, rufen Sie das Programm mysql auf und übergeben als Parameter den Namen des Benutzers, mit dem Sie arbeiten möchten. Für die Systemverwaltung ist das der Benutzer root. Über den Parameter -p weisen Sie das Programm an, das Passwort des Benutzers über die Kommandozeile abzufragen. # mysql -u root -p Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 13 Server version: 5.0.51a-3ubuntu5.1 (Ubuntu) Type 'help;' or '\h' for help. Type '\c' to clear the buffer. mysql> show status like 'Table%'; +-----------------------+-------+ | Variable_name | Value | +-----------------------+-------+
195
4.2
4
Serverdienste
| Table_locks_immediate | 35456 | | Table_locks_waited | 5346 | +-----------------------+-------+ 2 rows in set (0.00 sec) mysql>
MySQL versucht standardmäßig über Reverse-Lookups DNS-Namen für die IPAdressen der zugreifenden Clients zu ermitteln. Hierfür gilt dasselbe wie für den Apache (siehe Abschnitt »DNS-Zugriffe« auf S. 170). Aus Performancegründen sollten Sie daher DNS-Lookups unterbinden. MySQL muss dazu mit dem Parameter --skip-name-resolve gestartet werden. Vorsicht mit DNS-Lookups Wenn Sie Benutzer für den Zugriff von bestimmten Hosts einrichten, achten Sie darauf, dass Sie nur IP-Adressen verwenden, denn ansonsten geht das Deaktivieren der DNSLookups nach hinten los: MySQL kann Benutzer, bei denen DNS-Namen im Host-Feld stehen, dann nicht mehr authentifizieren.
Beim Betrieb eines LAMP-Systems müssen Sie neben dem Speicherverbrauch des Apache (siehe 163) auch den Speicherverbrauch des MySQL-Servers im Auge behalten. Dieser setzt sich aus verschiedenen Einzelfaktoren zusammen, die Sie über das Setzen entsprechender Variablen beeinflussen können, allerdings gilt auch hier Fingerspitzengefühl, um einen idealen Mittelweg zwischen optimaler Performance und minimalem Speicherverbrauch zu finden. Der Speicherverbrauch von MySQL setzt sich aus dem der verschiedenen Puffer zusammen, die für die Verwaltung von Daten und für die einzelnen Datenbankverbindungen mit den Clients verwendet werden. Die Größen dieser Puffer werden über Variablen in der zentralen Konfigurationsdatei von MySQL gesetzt. Diese ist bei Ubuntu und bei Gentoo die Datei /etc/mysql/my.cnf. Über phpMyAdmin können Sie über den Punkt MySQL-System-Variablen anzeigen auf der Startseite eine Übersicht über alle gesetzten Variablen und ihre Werte erhalten (siehe Abbildung 4.34). Bei der Verwendung von MyISAM-Tabellen ist der Puffer für die Indizes der Tabellen derjenige mit den größten Auswirkungen auf die Performance und sollte daher ausreichend groß bemessen sein. Festgelegt wird die Größe des Puffers über die Variable key_buffer. Bei Ubuntu und Gentoo ist der Standardwert 16 MB, was für einen gut beschäftigten Datenbankserver viel zu wenig ist. Die MySQL-Dokumentation spricht von einem Wert von 25 % des auf einem System verfügbaren Speichers, was bei einem System mit 4 GB Hauptspeicher 1 GB wäre (der Puffer darf maximal 4 GB groß sein). Aus meiner persönlichen Erfah-
196
Datenbanken
rung im Betrieb von Hochlastservern möchte ich diese Aussage etwas relativieren. 128–256 MB Puffergröße sind auf einem gut ausgelasteten System schon ausreichend, immerhin benötigen die anderen Prozesse auf dem System auch noch Speicher. MySQL erzeugt für jede Verbindung einen eigenen Thread, der Schlüsselpuffer wird von allen Threads gemeinsam benutzt.
Abbildung 4.34
Die MySQL-Variablen in phpMyAdmin
Ein Thread repräsentiert eine Verbindung von einem Client. Der Speicherverbrauch eines Threads setzt sich aus dem Stapel zusammen (thread_stack), dem Verbindungs- und Ergebnispuffer (net_buffer_length). Unter Ubuntu ist der Stapel in der Konfigurationsdatei auf 128 KB konfiguriert, unter Gentoo ist er auf dem Standardwert belassen (192 KB). Der Verbindungs- und Ergebnispuffer beträgt bei Ubuntu 16 KB, bei Gentoo 8 KB. Der Wert kann bis zur Größe der Variable max_allowed_packet wachsen. Diese ist bei Ubuntu auf 16 MB eingestellt, bei Gentoo auf 8 MB. Offensichtlich verfolgen die Maintainer der beiden Distributionen verschiedene Ansätze zur Speicheroptimierung von MySQL.
197
4.2
4
Serverdienste
Für jeden lesenden Zugriff einer Verbindung auf eine Tabelle reserviert der betreffende Thread einen Lesepuffer (read_buffer_size), bei Ubuntu 131 KB, bei Gentoo 262 KB. Bei wahlfreiem Zugriff auf eine Tabelle wird ein weiterer Lesepuffer reserviert, repräsentiert durch die Variable read_rnd_buffer_size (262 KB bei Ubuntu, 524 KB bei Gentoo). Zum Sortieren von Daten (select * from foo order by bar asc) reserviert ein Thread noch die in der Variable sort_ buffer_size definierte Menge an Speicherplatz. Bei Gentoo ist diese Größe auf 512 KB gesetzt, bei Ubuntu auf 2 MB. Für hohe Performance bei Webapplikationen, die sich in der Regel dadurch auszeichnen, dass die große Mehrzahl der Zugriffe nur lesend stattfindet, bietet MySQL einen Cache, in dem die Ergebnisse von Abfragen zwischengespeichert werden. Schickt ein Client eine Anfrage, versucht MySQL, diese Anfrage zuerst aus dem Cache zu bedienen. Erst wenn das fehlschlägt, greift MySQL auf die Datendatei auf der Festplatte zu und führt die Abfrage auf der Zieltabelle aus. Die Größe des Caches hat unmittelbaren Einfluss auf die Performance der Datenbank und auf die Last, welche die Datenbank auf dem System erzeugt. Kann die Datenbank einen Großteil der Anfragen aus dem Cache bedienen, senkt das ganz erheblich die Antwortzeiten und den Festplatten-I/O. Dafür muss der Cache, repräsentiert durch die Variable query_cache_size, allerdings ausreichend groß dimensioniert sein. Ubuntu spendiert dem Cache ganze 16 MB, Gentoo hat den Cache deaktiviert (query_cache_size = 0). Bei einem stark belasteten System mit ausreichend Speicher kann die Cache-Größe gerne 256 MB oder mehr sein. Wie effizient der Cache arbeitet, können Sie über phpMyAdmin erfahren. Über den Punkt MySQL-Laufzeit-Informationen anzeigen auf der Startseite kommen Sie zur Anzeige der Betriebsparameter. Der Abschnitt Abfragencache hält alle Informationen über den Cache bereit. Über die Angaben zur Auslastung und die Anzahl der Treffer können Sie auf die ideale Größe des Caches schließen. Experimentieren Sie ruhig mit der Cache-Größe, der ideale Wert hängt von Anzahl und Art der Abfragen ab, was wiederum von den auf dem Server betriebenen Webapplikationen abhängt. Diese Daten lassen sich auch über die Kommandozeile ermitteln, interessant ist dies vor allem für die automatisierte Abfrage per Skript: # mysql -u root -p Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 10 Server version: 5.0.54-log Gentoo Linux mysql-5.0.54 Type 'help;' or '\h' for help. Type '\c' to clear the buffer. mysql> show variables;
Wie beim Apache können Sie nun auch den Speicherverbrauch des MySQL-Servers berechnen. Dieser setzt sich aus den globalen Puffern und den Puffern pro Verbindung zusammen. Letztere multipliziert mit der Anzahl der erlaubten Verbindungen und das Ergebnis mit der Summe der globalen Puffer addiert, ergibt annähernd den Speicherverbrauch des Servers. Der Speicherverbrauch der Threads unterscheidet sich zwischen Ubuntu und Gentoo ganz erheblich. Allein die Größe von sort_buffer_size erzeugt einen Unterschied von 1,5 MB. Insgesamt addiert sich die Threadgröße unter Ubuntu auf knapp 2,5 MB, wobei der Verbindungspuffer auf bis zu 16 MB anwachsen kann, damit also 18,5 MB maximal pro Verbindung möglich sind. Unter Gentoo beträgt die minimale Threadgröße 1,5 MB, die maximale 9,5 MB. Welche der beiden Konfigurationen besser ist, kann nicht allgemeingültig beantwortet werden, das hängt zu sehr von den jeweiligen Rahmenbedingungen ab. Auf jeden Fall können Sie berechnen, wie viel Speicher der MySQL-Server bei Vollauslastung benötigt. Bei beiden Distributionen ist die maximale Anzahl von Verbindungen, festgelegt durch die Variable max_connections, 100. Damit beträgt der Speicherverbrauch des MySQL-
199
4.2
4
Serverdienste
Servers unter Ubuntu bei Vollauslastung ca. 282 MB, vorausgesetzt, jeder Thread verbraucht nur den Minimalwert an Speicher. Falls jeder Thread den vollen Sortierpuffer belegt, wächst der Speicherverbrauch bei Vollauslastung auf satte 1,8 GB! Bei Gentoo beträgt der minimale Speicherverbrauch bei Vollauslastung 166 MB, der maximale 966 MB. Tipp fürs Tuning Lassen Sie dem Server nicht zu viel Spielraum bei der Speicherbelegung. Ein Sortierpuffer von 16 MB ist spendabel, dadurch wird der Speicherverbrauch des Systems aber unkalkulierbar volatil. Um einen Systemstillstand durch zu hohen Speicherverbrauch zu vermeiden, müssen Sie bei der Dimensionierung der Puffer immer mit dem Schlimmsten rechnen, dem größtmöglichen Speicherverbrauch. Halten Sie die threadspezifischen Puffer klein, geben Sie dem Server einen großen Query-Cache, und beobachten Sie die Systeminformationen in phpMyAdmin. Datenbankoptimierung ist eine Wissenschaft für sich und hängt zu 99 % von der Art der in der Datenbank vorgehaltenen Daten und der darauf zugreifenden Applikationen ab. Der einzige allgemeingültige Tipp kann daher nur der sein, lieber Puffer und Anzahl der Verbindungen zu klein zu halten als zu groß, denn wenn der Speicher ausgeht und das Betriebssystem mit Swappen anfängt, steht Ihre Website.
Backup Das Thema Backup ist bei einer Datenbank von großer Bedeutung, denn im Unterschied zum Backup von Dateisystemen kann man bei einer Datenbank nicht einfach die Datendateien kopieren, um ein Backup anzufertigen. Das würde nur dazu führen, dass man im besten Fall einen inkonsistenten Datenbestand sichert, im schlimmsten Fall kann man mit den Dateien gar nichts anfangen, da die Datenbank eine Zugriffssperre darauf besitzt und man die Dateien gar nicht kopieren darf. Für MySQL existieren zwei Programme zum Durchführen von Backups. Zwar können Sie über phpMyAdmin händisch ein Dump aller Datenbanken erzeugen, aber das ist weder komfortabel, noch lässt es sich automatisieren. mysqlhotcopy ist ein Perl-Skript, das ein Online-Backup von MyISAM-Tabellen – und nur von diesen – erlaubt. mysqlhotcopy ist Bestandteil des MySQL-Paketes, so dass Sie für die Benutzung keine weitere Software installieren müssen. Das andere Programm ist mysqldump, mit dem Sie SQL-Dumps einer oder mehrerer Datenbanken erzeugen können. Es gibt drei Nachteile bei mysqlhotcopy. Der erste ist, dass es nur MyISAM-Tabellen sichern kann. Solange Sie nur Tabellen solchen Typs verwenden, ist der Nachteil nicht schwerwiegend. Der zweite Nachteil ist, dass das Programm nur lokal ausgeführt und nicht für die Sicherung einer Remote-Datenbank verwendet
200
Datenbanken
werden kann. Aber auch dieser Nachteil lässt sich verschmerzen. Richten Sie einfach einen Cron-Job ein, der regelmäßig mit mysqlhotcopy Ihre Datenbanken sichert, und Sie sind auf der sicheren Seite. Der wohl gewichtigste Nachteil ist die Unhandlichkeit des Programms. Es benötigt für den Zugriff auf die Datenbankdateien entsprechende Leserechte im Dateisystem, und obendrein können Sie dem Programm das Passwort für den zu verwendenden MySQL-Benutzer nicht interaktiv, sondern nur im Klartext als Kommandozeilenparameter übergeben. Dies hat bei der Verwendung von Skripten den eklatanten Nachteil, dass das entsprechende Skript das Passwort im Klartext enthält. Obendrein können Kommandozeilenargumente über den Befehl ps ausgelesen werden, womit ein anderer Benutzer des Servers möglicherweise in den Besitz des Passwortes gelangen kann. Nachfolgend wird die Ausgabe des psBefehls gezeigt, der während der Ausführung von mysqlhotcopy gestartet worden ist: # ps al|grep mysqlhot 0 0 4769 4677 20 0 6572 3660 R+ pts/ 0 0:00 /usr/bin/perl -w /usr/bin/mysqlhotcopy -u root p 1234qwer mysql test/ --allowold
Sie sehen alle Kommandozeilenparameter – auch das Passwort des MySQL-Administrators. Neben der Ausgabe über ps stehen die Kommandozeilenparameter jedes Programms unter Linux im proc-Verzeichnis des jeweiligen Prozesses in der Datei cmdline, auszulesen mit dem Befehl cat /proc//cmdline ( steht dabei für die PID des betreffenden Prozesses). Glücklicherweise erlaubt mysqlhotcopy das Verwenden eine Konfigurationsdatei, in der das Passwort abgelegt sein kann. Das ist zwar nicht optimal, aber immerhin können Sie diese Datei durch das Setzen möglichst restriktiver Zugriffsrechte vor unbefugtem Zugriff schützen. Die Verwendung von mysqlhotcopy ist simpel. Als Parameter erwartet das Programm den zu verwendenden MySQL-Benutzer samt Passwort, die zu sichernde Datenbank und das Verzeichnis, in dem es die Sicherung ablegen soll. Um die Datenbank mysql zu sichern, ist folgender Befehl nötig: mysqlhotcopy -u root -p 1234qwer mysql backup/ --allowold
Beachten Sie, dass der Benutzer, der das Skript ausführt, ausreichende Zugriffsrechte für die Datenverzeichnisse und -dateien der zu sichernden Datenbank haben muss, in der Regel ist das der Benutzer mysql: # dir /var/lib/mysql/mysql/ total 1000
Entweder führen Sie das Backup als Root-Benutzer durch, der Root-Zugriffe auf alle Verzeichnisse und Dateien hat, oder als Benutzer mysql. Da (automatisierte) Arbeiten mit Root-Rechten die Gefahr bergen, durch Fehler oder Manipulationen nachhaltige Probleme zu verursachen , ist es ratsam, das Datenbank-Backup mit den Rechten des Benutzers mysql durchzuführen. Unter Ubuntu und Gentoo besitzt der Benutzer mysql keine Shell, um Sicherheitsprobleme durch einen kompromittierten MySQL-Server zu vermeiden. Glücklicherweise sind bei beiden Distributionen die Dateisystemrechte der MySQL-Datenverzeichnisse so gesetzt, dass auch Mitglieder der Gruppe mysql auf die Daten zugreifen dürfen. Daher ist die einfachste und sicherste Methode für das Durchführen von Backups das Anlegen eines neuen Benutzers genau für diesen Zweck. Dieser Benutzer muss lediglich zur Gruppe mysql gehören, weitere Anforderungen gibt es nicht. Erzeugen können Sie den Benutzer mit dem folgenden Befehl: useradd -d /home/mysqlbackup -g mysql -s /bin /bash -m mysqlbackup
Das Home-Verzeichnis des Benutzers ist /home/mysqlbackup. Den Ort können Sie beliebig variieren, je nachdem, wo der Benutzer das Datenbank-Backup ablegen soll. Anschließend können Sie testweise ein Backup der Datenbank mysql erzeugen: # su - mysqlbackup mysqlbackup@hardy:~$ mysqlhotcopy -u root -p 1234qwer mysql backup/ Locked 17 tables in 0 seconds. Flushed tables (`mysql`.`columns_priv`, `mysql`.`db`, `mysql`.`func`, `mysql`.`help_category`, `mysql`.`help_keyword`, `mysql`.`help_relation`, `mysql`.`help_topic`, `mysql`.`host`, `mysql`.`proc`, `mysql`.`procs_priv`, `mysql`.`tables_priv`, `mysql`.`time_zone`, `mysql`.`time_zone_leap_second`, `mysql`.`time_zone_name`, `mysql`.`time_zone_transition`, `mysql`.`time_zone_transition_type`, `mysql`.`user`) in 0 seconds.
202
Datenbanken
Copying 51 files... Copying indices for 0 files... Unlocked tables. mysqlhotcopy copied 17 tables (51 files) in 1 second (1 seconds overall). mysqlbackup@hardy:~$
Die Kontrolle des Zielverzeichnisses ergibt: mysqlbackup@hardy:~$ ls -la backup/mysql/ total 1000 drwxr-x---+ 2 mysqlbackup mysql 4096 2008-07-06 drwxr-xr-x+ 3 mysqlbackup mysql 4096 2008-07-06 -rw-rw----+ 1 mysqlbackup mysql 8820 2008-06-29 columns_priv.frm -rw-rw----+ 1 mysqlbackup mysql 0 2008-06-29 columns_priv.MYD -rw-rw----+ 1 mysqlbackup mysql 1024 2008-06-29 columns_priv.MYI -rw-rw----+ 1 mysqlbackup mysql 9494 2008-06-29 -rw-rw----+ 1 mysqlbackup mysql 1314 2008-07-01 -rw-rw----+ 1 mysqlbackup mysql 4096 2008-07-01 [...]
Die Dateien und Werte stimmen mit denen der Ursprungsdateien im mysqlVerzeichnis /var/lib/mysql/mysql überein. Nur der Vollständigkeit halber: Eine MyISAM-Datenbank besteht immer aus drei Dateien. Alle drei Dateien tragen den Namen der Datenbank und unterscheiden sich durch ihre Endungen (.frm, .MYD und .MYI). Beachten Sie dabei die Groß- und Kleinschreibung der Dateinamen und -endungen, da MySQL eine Datenbank nur dann erkennt, wenn Großund Kleinschreibung korrekt sind. Warum so kompliziert? Möglicherweise fragen Sie sich, warum das Backup so kompliziert mit mysqlhotcopy erfolgen muss, wenn das Programm doch sowieso nur die Datendateien kopiert. Die Antwort ist einfach: Das händische Kopieren der Datendateien auf DateisystemEbene zur Sicherung ist durchaus dazu geeignet, ein Backup der Datenbank anzulegen. Bedenken Sie dabei aber, dass der MySQL-Server dafür nicht laufen darf, um Zugriffsprobleme und Inkonsistenzen im Datenbestand zu vermeiden. Es kann ja durchaus passieren, dass ein Client gerade dann schreibend auf eine Datenbank zugreift, wenn die Datei kopiert wird. Die Zieldatei ist dann entweder komplett defekt oder enthält unvollständige Daten. Beide Zustände sind für ein Backup eher hinderlich.
203
4.2
4
Serverdienste
Bei kleinen Datenbeständen kann das Anhalten des MySQL-Servers und das anschließende Kopieren der Daten noch eine Alternative zur Verwendung von mysqlhotcopy sein. Das Kopieren kleiner Dateien ist in wenigen Sekunden erledigt. Wenn eine Datenbank aber mal auf viele Giga- oder Terabytes angewachsen ist, werden Sie die Arbeit von mysqlhotcopy schätzen lernen, denn den Datenbankserver nur für ein Backup eine halbe Stunde herunterzufahren, ist nicht mehr zeitgemäß. mysqlhotcopy sperrt selektiv die aktuell zu sichernde Datenbank für schreibenden Zugriff und kopiert die Datendateien weg. Auf diese Weise wird das Herunterfahren des gesamten MySQL-Servers vermieden.
mysqlhotcopy hat einen weiteren Nachteil: Es kann nicht automatisch alle Datenbanken des MySQL-Servers sichern. Sie müssen die zu sichernde Datenbank explizit angeben, was ein automatisches Backup schwierig macht. Sie können aber das nachstehende Skript verwenden, das alle Datenverzeichnisse von MySQL durchsucht, daraus eine Liste der zu sichernden Datenbanken erzeugt und diese dann mit mysqlhotcopy sichert. Voraussetzung sind die Perl-Module Time::localtime und Unix::Syslog und natürlich das Anpassen der Einstellungen an Ihre Gegebenheiten. #!/usr/bin/perl -w # Backup all mysql databases using mysqlhotcopy # Klaus Rodewig =pod =head1 NAME mysqlbackup =head1SYNOPSIS mysqlbackup.pl =head1DESCRIPTION Backup all mysql databases using mysqlhotcopy =head1Autor Klaus Rodewig =cut use use use use
# settings my $DataPath = "/var/lib/mysql/"; my $BackupPath = "/home/mysqlbackup/backup/"; my $DBUser = "root"; my $DBPass = "1234qwer"; my $mysqlhotcopy = "/usr/bin/mysqlhotcopy"; my $BackupCmd1 = "mysqlhotcopy -u $DBUser -p $DBPass";
204
Datenbanken
my $BackupCmd2 = "$BackupPath --allowold"; my $SyslogIdent = "MySQL-Backup"; my $SyslogString; my $StartTime; my $StopTime; my $UsedTime; my $GlobalStartTime = `date +%s`; my $GlobalStopTime; my $GlobalUsedTime; # Syslog-Routine sub Syslog { my $String = shift; openlog($SyslogIdent, LOG_PID, LOG_LOCAL7); syslog(LOG_INFO, $String); closelog; } # programm Syslog("Starte Backup"); opendir(DIR, $DataPath) or die "Konnte Verzeichnis nicht oeffnen: $!"; while (defined(my $file = readdir(DIR))){ if (-d "$DataPath/$file" && $file ne "." && $file ne ".."){ my $BackupCmd = "$BackupCmd1 $file $BackupCmd2"; Syslog("Sicherung von DB \"$file\" ..."); $StartTime = `date +%s`; $StopTime = `date +%s`; $UsedTime = $StopTime - $StartTime; Syslog("Sicherung von DB \"$file\" beendet."); Syslog("Dauer: $UsedTime Sekunden."); } } closedir(DIR); $GlobalStopTime = `date +%s`; $GlobalUsedTime = $GlobalStopTime - $GlobalStartTime; Syslog("Backup beendet. Dauer: $GlobalUsedTime Sekunden.");
Fortschritt und Ergebnis seiner Arbeit sendet das Skript an den lokalen SyslogServer. Ein unbestreitbarer Vorteil von mysqlhotcopy ist die unmittelbare Verfügbarkeit des Backups. Sie müssen lediglich die Datendateien in das entsprechende Verzeichnis kopieren, den MySQL-Server starten, und schon stehen die Daten vom Zeitpunkt des Backups an zur Verfügung. Durch selektives Zurückspielen von Da-
205
4.2
4
Serverdienste
tendateien können auch einzelne Datenbanken gezielt wiederhergestellt werden – es besteht keine Notwendigkeit, das gesamte Backup zurückzuspielen. Durch das direkte Sichern der Datendateien ist mysqlhotcopy sehr performant. Der Datenbankserver selbst wird nur für das Sperren der Tabellen in Anspruch genommen, die Sicherung hingegen läuft ausschließlich über das Dateisystem. Im Gegensatz dazu können Sie mit dem Programm mysqldump SQL-Dumps von Datenbanken erstellen. Nachstehend ein Dump der Datenbank »foo«: mysqlbackup@hardy:~/backup$ mysqldump -u root -p foo Enter password: -- MySQL dump 10.11 --- Host: localhost Database: foo -- ------------------------------------------------------- Server version 5.0.51a-3ubuntu5.1 /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; /*!40101 SET NAMES utf8 */; /*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; /*!40103 SET TIME_ZONE='+00:00' */; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; --- Table structure for table `bar` -DROP TABLE IF EXISTS `bar`; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `bar` ( `ID` int(11) NOT NULL, `Text` varchar(50) collate utf8_unicode_ci NOT NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; SET character_set_client = @saved_cs_client; --
206
Datenbanken
-- Dumping data for table `bar` -LOCK TABLES `bar` WRITE; /*!40000 ALTER TABLE `bar` DISABLE KEYS */; INSERT INTO `bar` VALUES (45,'54'); /*!40000 ALTER TABLE `bar` ENABLE KEYS */; UNLOCK TABLES; /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!40101 /*!40014 /*!40014 /*!40101 /*!40101 /*!40101 /*!40111
Eine ganze Menge Text für eine kleine Datenbank mit nur einem Eintrag. Daran offenbart sich das Problem von mysqldump: Es belastet den MySQL-Server enorm, da dieser die Daten in SQL exportieren muss. Für die komplette Sicherung großer Datenbestände ist das Programm daher vollkommen ungeeignet. Praktisch ist es, um Daten oder Strukturen für Installationsskripte zu exportieren, für ein Backup sollten Sie aber lieber mysqlhotcopy verwenden.
4.2.2
PostgreSQL
Wie so häufig in der Geschichte der Technik setzt sich in der Masse nicht immer das technisch bessere Produkt durch, sondern ein technisch weniger ausgereiftes. Video-Freunde aus den 70er Jahren mögen sich noch an den Sieg des technisch unterlegenen VHS-Formates über das Betamax-Format erinnern. Apple-Benutzer trauern heute noch darüber, dass Windows den Kampf um den Desktop gewonnen hat – obwohl technisch das vermeintlich schlechtere System –, und auch im Bereich der Datenbanken gibt es diese Konkurrenz zwischen Systemen. Als MySQL Mitte der 90er Jahre populär wurde, gab es schon länger das PostgresProjekt, eine quelloffene Implementierung eines DBMS, das neben umfassender Standardkonformität auch Merkmale wie Transaktionen und referenzielle Integrität aufweisen konnte, Punkte, die bei MySQL erst Jahre später implementiert worden sind. Dass sich MySQL so schnell durchsetzen konnte, mag an den gut dokumentierten und funktionierenden Schnittstellen gelegen haben, die von Anfang an für die Datenbank verfügbar waren, insbesondere für PHP. Darüber hin-
207
4.2
4
Serverdienste
aus war MySQL seit jeher für den Einsatzzweck im Web optimiert, d. h. hohe Performance bei vielen gleichzeitigen lesenden Zugriffen. Postgres, in den Anfangszeiten als Postgres95 bekannt, heißt mittlerweile PostgreSQL und ist für zahlreiche Plattformen verfügbar, unter anderem auch für Linux. Wenn es funktional etwas mehr und zuverlässiger sein soll, dann ist PostgreSQL die erste Wahl. Transaktionsbasierte Operationen sind für Anwendungen, bei denen es auf unbedingte Zuverlässigkeit ankommt, wie z. B. Shop-Systeme, unabdingbar. Im Zusammenhang mit Transaktionen fällt häufig der Begriff des ACID-Systems. ACID steht dabei für die Anfangsbuchstaben der Begriffe Atomicity, Consistency, Isolation und Durability: 왘
Atomicity (Atomarität): Eine Transaktion ist nicht aufteilbar. Kann eine Transaktion nicht abgeschlossen werden, gilt sie als nicht durchgeführt. Nur vollständig abgeschlossene Transaktionen sind gültig und werden im Datenbestand gespeichert.
왘
Consistency (Konsistenz): Die Konsistenz des Datenbestandes muss zu jedem Zeitpunkt gewährleistet sein. Durchgeführte und abgebrochene Transaktionen dürfen den Datenbestand nicht in einem inkonsistenten Zustand hinterlassen.
왘
Isolation: Gleichzeitig ablaufende Transaktionen dürfen keinen Einfluss aufeinander ausüben.
왘
Durability: Durchgeführte und gültige Transaktionen müssen dauerhaft im Datenbestand gespeichert sein.
Im Zusammenhang mit Transaktionen ist der Begriff Rollback von großer Bedeutung. Ein Rollback setzt den Datenbestand wieder in den Ausgangsstatus zurück, wenn eine Transaktion abgebrochen, also nicht gültig beendet wurde. Einen ähnlichen Mechanismus verwenden Journaling-Dateisysteme, bei denen Schreiboperationen auch atomar sind und fehlgeschlagene Operationen, beispielsweise durch einen Systemabsturz verursacht, wieder rückgängig gemacht und das Dateisystem wieder in einen konsistenten Zustand gebracht werden kann. Installation und Konfiguration Unter Ubuntu 8.04 haben Sie die Wahl zwischen PostgreSQL in der Version 8.2 und 8.3. Sofern keine triftigen Gründe für die Verwendung von Version 8.2 sprechen, nehmen Sie 8.3. Die Installation ist, wie von Ubuntu gewöhnt, einfach: # sudo apt-get install postgresql-8.3 apt wird neben dem Serverpaket auch die Pakete postgresql-client-8.3 postgresql-client-common und postgresql-common installieren, in denen die für
208
Datenbanken
den Betrieb von PostgreSQL notwendigen Bibliotheken und Tools enthalten sind. Nach der Installation der Pakete ist der Datenbankserver einsatzbereit und für den automatischen Start im Standard-Runlevel eingetragen. Unter Gentoo müssen Sie, um von PHP aus auf PostgreSQL zugreifen zu können, zunächst die USE-Variable in der Datei /etc/make.conf um das Schlüsselwort postgres erweitern. # cat /etc/make.conf | grep USE USE="postgres apache2 mysql pam ssl xml xml2 suhosin php5 ctype pcre session unicode"
Anschließend emergen Sie PHP und starten danach den Apache neu, um das geänderte PHP-Modul zu laden. # sudo emerge php
Um PostgreSQL zu installieren, emergen Sie das Paket postgres. Portage wird weitere Pakete installieren wollen, beantworten Sie die entsprechende Frage mit Yes. # emerge -av postgresql These are the packages that would be merged, in order: Calculating dependencies... done! [ebuild N ] dev-libs/libgpg-error-1.6 USE="nls" 374 kB [ebuild N ] dev-python/egenix-mx-base-2.0.5 572 kB [ebuild N ] dev-libs/libgcrypt-1.4.0-r1 USE="nls -bindist idea" 943 kB [ebuild N ] dev-libs/libxslt-1.1.22 USE="crypt python -debug examples" 2,718 kB [ebuild N ] dev-db/postgresql-8.0.15 USE="kerberos nls pam perl python readline ssl xml zlib -doc -pg-intdatetime (-selinux) tcl -test" 0 kB Total: 5 packages (5 new), Size of downloads: 4,605 kB Would you like to merge these packages? [Yes/No] Yes [...]
Im Anschluss an die Installation erstellen Sie mit dem folgenden Befehl eine Grundkonfiguration des PostgreSQL-Servers: # emerge postgresql –config Configuring pkg... * Creating the data directory ... * Initializing the database ... The files belonging to this database system will be owned by user "postgres". This user must also own the server process.
209
4.2
4
Serverdienste
The database cluster will be initialized with locale C. [...]
Wichtig ist der Hinweis zum Abschluss der Konfiguration: WARNING: enabling "trust" authentication for local connections You can change this by editing pg_hba.conf or using the -A option the next time you run initdb.
Dieser Hinweis wird im folgenden Abschnitt bei der Installation von phpPgAdmin wichtig. Erzeugen Sie noch die notwendigen symbolischen Links für den automatischen Start des Datenbankservers, dann ist die Installation bereits vollständig: # sudo rc-update add postgresql default * postgresql added to runlevel default
phpPgAdmin unter Ubuntu Da die Administration über die Kommandozeile bei PostgreSQL genauso mühsam ist wie bei MySQL, sollten Sie für die Administration der Datenbank die Weboberfläche phpPgAdmin installieren, das Pendant zu phpMyAdmin. Sowohl für Ubuntu als auch für Gentoo steht ein Paket zur Verfügung, so dass Sie bequem auf den jeweiligen Paketmanager zurückgreifen können. Unter Ubuntu installieren Sie das Paket wie gewohnt mit apt-get: # sudo apt-get install phppgadmin
Im Gegensatz zur Installation von phpMyAdmin müssen Sie bei der Installation von phpPgAdmin den symbolischen Link auf die Apache-Konfiguration selbst setzen. # cd /etc/apache2/conf.d # sudo ln –s ../../phppgadmin/apache.conf phppgadmin.conf
Interessanterweise ist die Konfigurationsdatei sehr restriktiv und erlaubt den Zugriff auf phpPgAdmin nur vom lokalen Host: order deny,allow deny from all allow from 127.0.0.0/255.0.0.0 allow from all
Das ist natürlich wenig hilfreich, wenn Sie über das Internet auf die Administrationsoberfläche zugreifen möchten. In diesem Fall kommentieren Sie die vier Zeilen einfach aus und starten den Apache neu.
210
Datenbanken
Standardmäßig darf sich der Benutzer postgres nicht über phpPgAdmin anmelden. Dies ist in der Konfigurationsdatei von phpPgAdmin geregelt. Um dieselbe Funktionalität zu erhalten, die auch phpMyAdmin bietet, also die Verwaltung des Datenbankservers mit allen Optionen, ist das Einloggen als Administrator-Benutzer aber unerlässlich. Passen Sie daher in der Datei /usr/share/phppgadmin/conf/ config.inc.php die Variable extra_login_security an, und setzen Sie den Wert von true auf false: $conf['extra_login_security'] = false;
Anschließend setzen Sie in der Datei, mit der die Authentifizierung des PostgreSQL-Servers gesteuert wird, die lokale Authentifizierung auf trust. Die Datei finden Sie unter /etc/postgresql/8.3/main/pg_hba.conf. In der Zeile … host
all
alle
127.0.0.1/32
md5
… ersetzen Sie den Wert md5 durch trust: host
all
alle
127.0.0.1/32
trust
Anschließend starten Sie den PostgreSQL-Server neu: # sudo /etc/init.d/postgresql-8.3 restart
Sie haben damit die Passwortüberprüfung für Verbindungen über die lokale Loopback-Schnittstelle als vertrauenswürdig eingestuft; für diese Verbindungen müssen Sie sich nicht mehr mit einem Passwort gegenüber dem Datenbankserver authentifizieren. Die Angabe des Benutzernamens ist ausreichend. Über die URL http://<servername>/phppgadmin können Sie nun die Administrationsoberfläche erreichen. Als Benutzernamen geben Sie postgres ein, das Passwort lassen Sie leer. Falls Sie SSL aktiviert haben, können Sie die Administration auch über eine HTTPS-Verbindung verwenden. Vergeben Sie nun über die Oberfläche ein Passwort für den Benutzer postgres. Dazu wählen Sie im rechten Teil des Fensters den Punkt Server aus, wählen in der folgenden Seite den lokalen Server mit dem Namen PostgreSQL aus und gehen in der dann erscheinenden Seite in die Benutzerverwaltung (Roles).
211
4.2
4
Serverdienste
Abbildung 4.36
Die Startseite von phpPgAdmin
Abbildung 4.37
Die Benutzerverwaltung von phpPgAdmin
212
Datenbanken
Über die Schaltfläche Ändern können Sie das Passwort des betreffenden Benutzers ändern. Wenn Sie das neue Passwort gesetzt haben, ändern Sie in der Datei /etc/postgresql/8.3/main/pg_hba.conf die eben bearbeitete Zeile … host
all
alle
127.0.0.1/32
trust
alle
127.0.0.1/32
md5
… zurück in … host
all
Der PostgreSQL-Server verlangt nun auch für lokale Verbindungen eine Authentifizierung mit Benutzername und Passwort. Passwort ändern mit psql Über die Kommandozeile können Sie das Passwort eines PostgreSQL-Benutzers mit dem Programm psql ändern. Starten Sie als Benutzer postgres psql, und ändern Sie mit dem Befehl \password das Passwort für den als Parameter übergebenen Benutzer.
phpPgAdmin unter Gentoo Um phpPgAdmin unter Gentoo zu installieren, verwenden Sie emerge: # emerge phppgadmin
Im Gegensatz zu Ubuntu wird bei Gentoo die Apache-Konfiguration automatisch angepasst, so dass Sie phpPgAdmin nach dem Installieren des Paketes direkt im Browser aufrufen können. Allerdings müssen Sie die Konfiguration von phpPgAdmin noch anpassen, da diese – wie bei Ubuntu – das Login des Benutzers postgres unterbindet. Ändern Sie dafür in der Datei /var/www/localhost/htdocs/ phppgadmin/conf/config.inc.php die Zeile … $conf['extra_login_security'] = true;
… in … $conf['extra_login_security'] = false;
Das weitere Vorgehen ist analog zu dem bei Ubuntu. Sobald Sie über die Oberfläche von phpPgAdmin ein Passwort für den Benutzer postgres vergeben haben, können Sie in der Datei /var/lib/postgresql/data/pg_hba.conf die Authentifizierung von trust auf MD5 ändern. Optimierung Für die Optimierung des PostgreSQL-Servers gelten dieselben allgemeinen Punkte wie zu MySQL im Abschnitt »Optimierung« (siehe Seite 193) beschrieben. Ausreichend Hauptspeicher, sinnvolle Partitionierung und eine schnelle Platte
213
4.2
4
Serverdienste
sind die halbe Miete für einen performanten Datenbankserver. Am stärksten macht sich bei PostgreSQL – wie bei anderen Datenbanken auch – ein effizientes Datenmodell und optimierte Programmierung der zugreifenden Clients bemerkbar. Sie können das Betriebssystem noch so sehr tunen – wenn Sie beim Aufruf einer einzigen Webseite 30 SQL-Statements an die Datenbank absetzen und Tabellen ohne Indizes verwenden, wird Ihnen die Datenbank relativ schnell um die Ohren fliegen. Daher ist das Thema Datenbanktuning in erster Linie ein Thema auf Anwendungsebene und nur zum Teil ein Thema des Administrators. Konfiguriert wird der PostgreSQL-Server über die Datei postgresql.conf. Diese befindet sich bei Ubuntu standardmäßig im Verzeichnis /etc/postgresql/8.3/main/. Unter Gentoo finden Sie diese Datei im Verzeichnis /var/lib/postgresql/data/. Wie bei Konfigurationsdateien unter Linux üblich, enthält jede Zeile der Datei eine Direktive. Viele der Direktiven sind entweder gut kommentiert oder selbsterklärend, so z. B. alle Direktiven, mit denen Datenverzeichnisse oder Netzwerkeinstellungen festgelegt werden. Eine vollständige Übersicht über alle Direktiven enthält die – im Übrigen sehr gute – Dokumentation des PostgreSQL-Projektes. Interessant für den Betrieb und das Tuning des PostgreSQL-Servers sind alle Direktiven, die Einfluss auf die Anzahl der möglichen Client-Verbindungen und den Speicherverbrauch dieser Verbindungen und des Servers selbst haben. Speicher ist der limitierende Faktor bei einem Datenbankserver, so dass Sie diese Einstellungen mit großer Sorgfalt vornehmen und im laufenden Betrieb ständig auf Verbesserungsmöglichkeiten hin untersuchen sollten. Die grundlegendste Einstellung von PostgreSQL ist die Anzahl der möglichen Client-Verbindungen. Diese können Sie über die Direktive max_connections bestimmen. Der Standardwert bei Ubuntu und Gentoo ist 100. Wie MySQL belegt PostgreSQL globalen Speicher, den der Serverprozess und die Verbindungen verwenden, und Speicher pro Verbindung. Die Direktive shared_buffers legt die Größe des für shared Memory reservierten Speichers fest, den der Datenbankserver belegt. Über diese shared Memory kommunizieren die Threads des Datenbankservers untereinander. Einen allgemeingültigen Richtwert für die Größe des shared Memorys gibt es nicht. Bei Ubuntu sind standardmäßig 24 MB konfiguriert, bei Gentoo 1 MB. Als groben Wert können Sie eine Größe von 15 % des verfügbaren Hauptspeichers festlegen. Verfügbar bezieht sich dabei nicht auf den freien Speicher. Der minimale Wert muss 128 KB betragen. Jede Verbindung belegt ca. 16 KB, so dass Sie mindestens die mit max_connections festgelegte Anzahl mal 16 KB konfigurieren sollten.
214
Datenbanken
Tuning mit Bedacht Bei allen Angaben zu Hardware-Ressourcen müssen Sie immer im Auge behalten, dass auf einem integrierten Webserver nicht nur ein Serverdienst allein aktiv ist. Auf einem LAMP-System laufen mindestens ein Webserver und ein Datenbankserver. Beim Tuning dieser Komponenten müssen Sie daher immer den Ressourcenbedarf der anderen Komponente mit einrechnen.
Über die Direktive temp_buffers wird der Speicherplatz festgelegt, den eine Verbindung temporär belegen kann. Der Standardwert ist 8 MB; dieser Wert ist für die Praxis gut gewählt und sollte nur bei besonderen Anforderungen, z. B. vielen umfangreichen SQL-Statements, angepasst werden. Für Sortieroperationen verwendet jede Verbindung einen eigenen Speicherbereich. Die Größe desselben können Sie über die Direktive work_mem festlegen. Der Standardwert bei Ubuntu und Gentoo ist 1 MB. Beachten Sie, dass eine Verbindung mehrere Sortieroperationen ausführen und dadurch mehrfach Speicherbereiche in der durch work_mem festgelegten Größe belegen kann. Wenn Ihre Applikation daher mit vielen Sortieroperationen auf der Datenbank arbeitet, kann ein zu großzügig bemessener Wert von work_mem schnell zum Kollaps des Servers führen. Interessant sind die Direktiven max_fsm_pages und max_fsm_relations. PostgreSQL schreibt Änderungen an Tabellen nicht unmittelbar auf die Festplatte. Das würde bei vielen Schreiboperationen zu einem unnötig hohen Festplatten-I/O führen und die Performance des Servers merklich negativ beeinflussen. PostgreSQL verwendet daher eine so genannte Free Space Map (FSM). In dieser FSM hält PostgreSQL fest, wenn ein Datensatz gelöscht worden ist, und verwendet den frei gewordenen Speicherplatz für nachfolgende Schreiboperationen. Ist die FSM zu klein, kann PostgreSQL den durch Löschoperationen frei werdenden Speicher nicht effizient verwalten und belegt dadurch unnötig viel Festplattenplatz – und führt wesentlich mehr Schreiboperationen auf der Festplatte durch als notwendig. Über die Direktive max_fsm_relations können Sie die maximale Anzahl von Relationen festlegen, die PostgreSQL in der FSM verwaltet. Aus diesem Wert ergibt sich der Wert der Direktive max_fsm_pages, mit der die maximale Anzahl von Speicherblöcken der Festplatte festgelegt wird, die PostgreSQL für die FSM verwenden darf. Der Standardwert vom max_fsm_relations ist 1.000, auch bei Ubuntu und Gentoo. max_fsm_pages muss mindestens max_fsm_relations multipliziert mit 16 betragen. Die Zuverlässigkeit von PostgreSQL resultiert nicht zuletzt aus der Verwendung von Write-Ahead-Logging (WAL). Darunter versteht man, dass Änderungen an
215
4.2
4
Serverdienste
den Datendateien erst in einer Logdatei vermerkt werden und diese Logdatei auf die Festplatte geschrieben werden muss, bevor die Änderungen auf die Festplatte geschrieben werden. PostgreSQL führt ein Redo-Log, das die Anforderungen des WAL erfüllt. Das Feintuning des WAL-Mechanismus ist eine Wissenschaft für sich, da es unmittelbare Auswirkungen auf Performance und Datensicherheit des PostgreSQL-Servers hat. Sie sollten daher nur in begründeten Ausnahmefällen Änderungen an den WAL-Einstellungen vornehmen. Die WAL-Dateien werden (normalerweise) im pg_xlog-Verzeichnis unterhalb des Datenverzeichnisses des PostgreSQL-Servers abgelegt. Jedes WAL-Segment ist 16 MB groß und besteht aus 8 KB großen Pages. Um Datensicherheit und Performance zu erhöhen, sollte das Verzeichnis mit den WAL-Dateien auf einer anderen Festplatte abgelegt werden als die eigentlichen Datendateien des PostgreSQL-Servers. Im Zusammenhang mit WAL sind die so genannten Checkpoints von großer Bedeutung. Ein Checkpoint ist der Zeitpunkt, zu dem Daten aus dem shared Memory auf die Festplatte geschrieben werden. Gleichzeitig wird in der Logdatei ein Checkpoint-Eintrag vermerkt. Nach einem Systemabsturz ist damit sichergestellt, dass alle bis zum letzten in der Logdatei vorhandenen Checkpoint geschriebenen Daten auch wirklich auf der Festplatte vorhanden sind. Der Datenbankserver schreibt nach der mit checkpoint_segments definierten Anzahl von Segmenten einen Checkpoint auf die Festplatte. Damit bei Datenbankservern mit wenigen Transaktionen trotzdem regelmäßig Checkpoints geschrieben werden, gibt es als zweite Direktive zur Steuerung von Checkpoints checkpoint_timeout, mit der Sie den Zeitraum zwischen zwei Checkpoints definieren können. Andersrum würde das ausschließliche Verwenden eines Timeouts bei einem Datenbankserver mit sehr vielen Transaktionen dazu führen, dass zwischen zwei Checkpoints sehr viele Transaktionen ablaufen würden. Im Falle eines Crashs würden daher entsprechend viele Transaktionen verlorengehen. Beide Direktiven sind mit Vorsicht zu genießen. Auf stark belasteten Servern kann das Verringern der Anzahl der zu schreibenden Checkpoints zu einer Entlastung des Systems führen. Allerdings erkaufen Sie diesen Vorteil dadurch, dass bei einem Systemausfall wesentlich mehr Daten verlorengehen. Auf der anderen Seite führt das vermehrte Schreiben von Checkpoints im Sinne der Datensicherheit zu einem stark erhöhten Festplatten-I/O. Dabei fällt neben dem Schreiben der eigentlichen Checkpoints noch zusätzlicher Festplatten-I/O dadurch an, dass bei der ersten Transaktion nach einem Checkpoint immer eine gesamte Page auf die Festplatte geschrieben wird.
216
Datenbanken
Die Direktive checkpoint_warnings kann Ihnen dabei helfen, eine gute Balance zwischen Datensicherheit und Performance zu finden. Damit legen Sie einen Zeitraum in Sekunden fest, den Sie als Schreibintervall für Checkpoints als ausreichend erachten – analog zu checkpoint_timeout. Schreibt der Datenbankserver aufgrund der Direktive checkpoint_segments innerhalb dieses Zeitraums mehr Checkpoints an, als erwartet oder erwünscht, wird eine Warnung ausgegeben. In diesem Fall sollten Sie die Direktive checkpoint_segments anpassen, deren Wert also vergrößern, da im vorgegebenen Zeitraum zu viele Transaktionen anfallen, so dass nicht checkpoint_timeout den für das Schreiben der Checkpoints relevanten Wert festlegt, sondern checkpoint_segments. Die auf diese Weise ermittelten Daten sind natürlich nur für das Verhalten des Datenbankservers zum Zeitpunkt der Untersuchung gültig. Eine ausgewogene Konfiguration für einen Datenbankserver unter Last kann für einen Datenbankserver im Normalzustand nicht ideal sein. Wägen Sie gut ab, für welchen Zustand Sie den Server optimieren möchten. Datensicherheit versus Performance Der große Vorteil von PostgreSQL gegenüber MySQL war schon immer die Datensicherheit. Sie sollten daher diesen Vorteil nicht leichtfertig für ein bisschen Performance aufs Spiel setzen.
Eine weitere Direktive, mit der Sie Einfluss auf das Verhalten des Datenbankservers in Bezug auf Checkpoints nehmen können, ist checkpoint_completion_ target. Diese Direktive legt fest, innerhalb welchen Zeitraums die Daten eines Checkpoints auf die Festplatte geschrieben werden. Je größer der Wert, desto größer der Zeitraum, das Schreiben der Daten wird also zeitlich gestreckt. Damit wird die Last durch das Schreiben der Daten verringert. Je höher die Last des Servers, desto größer sollten Sie den Wert setzen. Bedenken Sie dabei aber, dass sich dadurch die Zeit für ein Recovery vergrößert, denn durch den verlängerten Schreibvorgang werden die zu schreibenden Daten auf mehr Segmente verteilt als bei einem möglichst kurzen Schreibvorgang. Aktuelle Einstellungen prüfen Die aktuellen Einstellungen des PostgreSQL-Servers können Sie im laufenden Betrieb über das Programm psql einsehen. Starten Sie das Programm als Benutzer postgres, und geben Sie die Liste aller gegenwärtigen Einstellungen mit dem Befehl show all; aus.
PostgreSQL 8.3 unter Gentoo Die unter Gentoo aktuelle stabile Version von PostgreSQL ist 8.0.15. Version 8.3.1 ist gegenwärtig noch als package.mask gekennzeichnet, d. h. für den Pro-
217
4.2
4
Serverdienste
duktivbetrieb nicht empfohlen. Um eine stabile und aktuelle Version von PostgreSQL zu installieren, können Sie auf der Website des PostgreSQL-Projektes9 den aktuellen Linux-Installer herunterladen und die Binärversion installieren. Damit ist Ihre PostgreSQL-Installation allerdings nicht mehr vom Gentoo-Paketmanager erfasst und wird dementsprechend auch nicht automatisch aktualisiert. Diese Arbeit müssen Sie folglich selbst übernehmen. Der Linux-Installer der Binärversion ist selbsterklärend. Starten Sie die Datei als root, und folgen Sie den Anweisungen. # ./postgresql-8.3.3-2-linux.bin ----------------------------------------------------------------Welcome to the PostgreSQL Setup Wizard. ----------------------------------------------------------------Please specify the directory where PostgreSQL will be installed. Installation Directory [/opt/PostgreSQL/8.3]: ----------------------------------------------------------------Please select a directory under which to store your data. Data Directory [/opt/PostgreSQL/8.3/data]: ----------------------------------------------------------------Please provide a password for the database superuser (postgres). Password : Retype password : ----------------------------------------------------------------Please select the port number the server should listen on. Port [5432]: ----------------------------------------------------------------Select the locale to be used by the new database cluster. Locale [1] C [2] POSIX Please choose an option [1] : 2 ----------------------------------------------------------------Procedural languages Select the procedural languages you would like to install into the template1 database. pl/pgsql [Y/n]: pl/Perl (trusted) [y/N]: pl/Perl (untrusted) [y/N]: pl/Python (untrusted) [y/N]: pl/Tcl (trusted) [y/N]: pl/Tcl (untrusted) [y/N]: ----------------------------------------------------------------Setup is now ready to begin installing PostgreSQL on your computer. 9 http://www.postgres.org/
218
Datenbanken
Do you want to continue? [Y/n]: ----------------------------------------------------------------Please wait while Setup installs PostgreSQL on your computer. Installing 0 % ______________ 50 % ______________ 100 % ######################################### ----------------------------------------------------------------Setup has finished installing PostgreSQL on your computer.
Die Installations- und Datenverzeichnisse können Sie bei der Installation selbst auswählen oder die Standardeinstellung übernehmen (/opt/PostgreSQL). Bedenken Sie, dass sich das Programmverzeichnis nicht automatisch im Suchpfad befindet. Sie müssen den Pfad also entweder in Ihre PATH-Umgebungsvariable aufnehmen oder stets den kompletten Pfad zu den entsprechenden Programmen angeben, z. B. /opt/PostgreSQL/8.3/bin/psql. Der Installer legt das Startskript in /etc/init.d/postgresql-8.3 an; für den automatischen Start des Datenbankservers müssen Sie noch für die korrekten Init-Links sorgen: # sudo rc-update add postgresql-8.3 default * postgresql-8.3 added to runlevel default
Backup Für die Sicherung der Daten des PostgreSQL-Servers stehen die gleichen Möglichkeiten zur Verfügung, die auch MySQL bietet, das Dumpen der Datenbanken und die Sicherung auf Dateisystem-Ebene durch Kopieren der Datendateien. Darüber hinaus bietet PostgreSQL aber noch die Möglichkeit einer kontinuierlichen Online-Sicherung, auch als Online-Archivierung oder Point in Time Recovery (PITR) bekannt. Für die konventionellen Methoden, SQL-Dump und Backup auf DateisystemEbene, gelten dieselben Einschränkungen wie zu MySQL im Abschnitt »Backup« auf Seite 200 beschrieben. Ein SQL-Dump ist hilfreich beim Einrichten neuer Datenbankserver, auf denen Datenbestände anderer Server verwendet werden sollen, für die Arbeit an Entwicklungssystemen etc. Für das Erzeugen von SQL-Dumps bringt PostgreSQL das Programm pg_dump mit. Alternativ können Sie auch SQL-Befehle über das Programm psql an den Datenbankserver schicken. Als Datei vorliegende SQL-Dumps können Sie mit dem Programm pg_restore in eine Datenbank importieren. Im Folgenden wird die Ver-
219
4.2
4
Serverdienste
wendung dieser Programme gezeigt. Erstellen Sie dazu mit phpPgAdmin eine neue Datenbank mit dem Namen »foo« (Abbildung 4.38).
Abbildung 4.38
Eine neue Datenbank
Nach dem Anlegen wählen Sie in der Übersicht über die Datenbanken die neue Datenbank aus und wählen in der Anzeige der Schemata das Standardschema public (Abbildung 4.39).
Abbildung 4.39
Das Standardschema der Datenbank
Innerhalb dieses Schemas können Sie über den gleichnamigen Punkt eine neue Tabelle erstellen. Geben Sie der Tabelle den Namen »Oink«, legen Sie zwei Spalten an, und fügen Sie noch den Kommentar »Foo« hinzu (Abbildung 4.40).
Abbildung 4.40
220
Eine neue Tabelle
Datenbanken
Im nächsten Dialog legen Sie die Eigenschaften der Spalten fest. Die erste Spalte ist vom Typ SERIAL. Als Spaltennamen vergeben Sie »ID«. Diese Spalte soll der Primärschlüssel der Tabelle sein, daher aktivieren Sie bitte die entsprechende Checkbox. Die zweite Spalte erhält den Namen »Name« und den Typ character varying und wird über die entsprechende Checkbox als eindeutiger Schlüssel festgelegt (Abbildung 4.41).
Abbildung 4.41
Die Spalten der neuen Tabelle
Nach Abschluss dieser Arbeit fügen Sie einen neuen Datensatz in die Tabelle ein. Dazu wählen Sie in der Übersicht über die Tabellen innerhalb der Datenbank »foo« den Button Einfügen. Da die Spalte ID vom Typ SERIAL ist, vergibt PostgreSQL den Wert für ID automatisch. Fügen Sie in das Feld für die Spalte Name einen beliebigen String-Wert ein (Abbildung 4.42).
Abbildung 4.42
Ein neuer Datensatz in der Tabelle
Um einen SQL-Dump der Tabelle zu erzeugen, melden Sie sich auf der Konsole als Benutzer postgres an. Am einfachsten geht das, wenn Sie als Benutzer root ein su - postgres ausführen. Einen SQL-Dump der neu angelegten Tabelle »foo« können Sie über den folgenden Befehl erzeugen. Über den Schalter -f werden die Daten in eine Datei umgeleitet.
221
4.2
4
Serverdienste
# pg_dump -f foo.sql foo
Die Datei foo.sql enthält anschließend alle SQL-Befehle, mit denen die Datenbank »foo« wiederhergestellt werden kann. Öffnen Sie die Datei in einem Editor, und Sie sehen, dass alle Operationen, die Sie zum Anlegen der Datenbank über phpPgAdmin durchgeführt haben, in SQL-Syntax abgebildet sind. --- PostgreSQL database dump -SET client_encoding = 'UTF8'; SET standard_conforming_strings = off; SET check_function_bodies = false; SET client_min_messages = warning; SET escape_string_warning = off; --- Name: foo; Type: COMMENT; Schema: -; Owner: postgres -COMMENT ON DATABASE foo IS 'bar'; SET search_path = public, pg_catalog; SET default_tablespace = ''; SET default_with_oids = false; --Name: Oink; Type: TABLE; Schema: public; Owner: postgres; Tablespac e: -CREATE TABLE "Oink" ( "ID" integer NOT NULL, "Name" character varying(20) ); ALTER TABLE public."Oink" OWNER TO postgres; --Name: TABLE "Oink"; Type: COMMENT; Schema: public; Owner: postgres -COMMENT ON TABLE "Oink" IS 'Foo'; --- Name: Oink_ID_ seq; Type: SEQUENCE; Schema: public; Owner: postgres -CREATE SEQUENCE "Oink_ID_seq" INCREMENT BY 1 NO MAXVALUE NO MINVALUE CACHE 1; ALTER TABLE public."Oink_ID_seq" OWNER TO postgres; --
222
Datenbanken
-- Name: Oink_ID_ seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres -ALTER SEQUENCE "Oink_ID_seq" OWNED BY "Oink"."ID"; --- Name: Oink_ID_ seq; Type: SEQUENCE SET; Schema: public; Owner: postgres -SELECT pg_catalog.setval('"Oink_ID_seq"', 1, true); --- Name: ID; Type: DEFAULT; Schema: public; Owner: postgres -ALTER TABLE "Oink" ALTER COLUMN "ID" SET DEFAULT nextval('"Oink_ID_ seq"'::regclass); --- Data for Name: Oink; Type: TABLE DATA; Schema: public; Owner: postgres -COPY "Oink" ("ID", "Name") FROM stdin; 1 Michnix \. --- Name: Oink_Name_ key; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: -ALTER TABLE ONLY "Oink" ADD CONSTRAINT "Oink_Name_key" UNIQUE ("Name"); --- Name: Oink_ pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: -ALTER TABLE ONLY "Oink" ADD CONSTRAINT "Oink_pkey" PRIMARY KEY ("ID"); --- Name: public; Type: ACL; Schema: -; Owner: postgres -REVOKE ALL ON SCHEMA public FROM PUBLIC; REVOKE ALL ON SCHEMA public FROM postgres; GRANT ALL ON SCHEMA public TO postgres; GRANT ALL ON SCHEMA public TO PUBLIC; --- PostgreSQL database dump complete --
223
4.2
4
Serverdienste
Eine Sache fällt direkt ins Auge. Die Datei mit den SQL-Daten ist umfangreich. 115 Zeilen für eine simple Datenbank mit einer Tabelle und einem Datensatz. Nun steigt die Größe des Dumps nicht proportional zur Anzahl der Datensätze, aber je größer die Datenbank, desto größer auch die SQL-Dumps. Um einen Dump zu erzeugen, mit dem eine Datenbank einfach wiederhergestellt werden kann, sollten Sie pg_dump den Schalter -Ft übergeben. Dadurch erzeugt pg_dump ein Tar-Archiv mit allen für ein Restore benötigten Daten. # pg_dump -Ft -f foo.tar foo
Den Inhalt des Archivs können Sie nun über das Programm pg_restore in eine beliebige Datenbank zurücksichern. Zunächst müssen Sie die Zieldatenbank anlegen: # createdb foo2
Anschließend laden Sie mit pg_dump den Inhalt des Archivs in diese Datenbank: # pg_restore -d foo2 foo.tar
Das Ergebnis lässt sich mit phpPgAdmin überprüfen. Die neue Datenbank »foo2« ist sofort sichtbar und hat die gleiche Größe wie die Datenbank »foo« (Abbildung 4.43).
Abbildung 4.43
Die neue Datenbank »foo2«
Genauso wie die Datenbank »foo« enthält auch die Datenbank »foo2« einen einzigen Eintrag: »Michnix« (Abbildung 4.44).
Abbildung 4.44
Ein Datensatz in der Datenbank »foo2«
Die Sicherung der Datenbank über SQL-Dumps ist unhandlich. Dasselbe gilt für die Sicherung auf Dateisystem-Ebene. Für diese Art der Sicherung muss der Datenbankserver angehalten werden. Die Downtime wächst damit proportional zur
224
Datenbanken
Datenmenge. Bei großen Datenbanken ist die Sicherung auf Dateisystem-Ebene daher rein praktisch gar nicht möglich, denn welcher Datenbankserver kann für ein Backup mal eben ein paar Stunden abgeschaltet werden? Im Büro-Umfeld, wo Anwender nur zu normalen Bürozeiten auf einer Datenbank arbeite, ist diese Art der Sicherung durchaus denkbar. Auf einen Zeitpunkt in der Nacht verlegt, stellt das Herunterfahren des Datenbankservers kein großes Problem dar – es ist ja ohnehin niemand da, der darauf zugreifen möchte. Anders verhält es sich im Internet. Eine Website muss normalerweise rund um die Uhr erreichbar sein. In Einzelfällen kann es Ausnahmen geben, aber eine Website, die täglich zwei Stunden wegen der Datensicherung nicht erreichbar ist, dürfte nicht auf große Gegenliebe bei den Benutzern stoßen. Ein weiteres Problem mit der Datensicherung über SQL-Dumps oder auf Dateisystem-Ebene ist die Tatsache, dass damit nur Komplettsicherungen gefahren werden können. Damit muss bei jeder Sicherung ein größerer Datenbestand gesichert werden, was die Dauer der Datensicherung ständig vergrößert. Glücklicherweise bietet PostgreSQL ein sehr effizientes und modernes Verfahren zur Sicherung der Daten, die Online-Sicherung. Diese basiert auf dem WAL-Mechanismus und baut auf den WAL-Logdateien auf. Diese Logdateien müssen für die Online-Sicherung dauerhaft archiviert werden, so dass im Falle eines Datenverlustes der Datenbestand der Datenbank aus diesen Logfiles wieder rekonstruiert werden kann. Um PostgreSQL für die Online-Sicherung einzurichten, gibt es drei Direktiven, die in der zentralen Konfigurationsdatei gesetzt sein müssen: archive_mode archive_command archive_timeout
Die erste Direktive muss für die Online-Sicherung auf on gesetzt sein. Damit wird der Datenbankserver überhaupt erst angewiesen, die WAL-Logdateien dauerhaft zu führen. Damit die WAL-Logdateien dauerhaft archiviert und nicht vom Datenbankserver überschrieben werden, muss der Server jede WAL-Datei nach dem Schreiben an einen »sicheren« Ort verschieben. Dazu dient die Direktive archive_command. Mit dieser Direktive definieren Sie einen Befehl, den der Datenbankserver ausführt, wenn eine WAL-Datei gefüllt ist und er eine neue beginnt. Ein solcher Befehl kann etwas in der folgenden Art sein: archive_command = 'cp %f /backup/'
Der Platzhalter %f steht für den Namen der abgeschlossenen WAL-Datei. Als weiteren Platzhalter können Sie %p verwenden, was für den gesamten Pfad der WAL-
225
4.2
4
Serverdienste
Datei steht. Da festverdrahtete Befehle in Konfigurationsdateien nicht empfehlenswert sind, können Sie der Direktive archive_command auch ein Skript übergeben, das der Datenbankserver zur Archivierung ausführt: archive_command = '/data/scripts/move_wal.sh'
Wertvolle Archive-Logs Bedenken Sie beim Erstellen des archive_command daran, dass Sie korrekte Kommandos verwenden und bei der Programmierung eigener Skripte unbedingt mit der Prüfung von Rückgabewerten arbeiten. Das Fehlen einer einzigen Logdatei kann die gesamte OnlineSicherung zerstören! Die WAL-Logdateien sind maximal 16 MB groß. Je nach Anzahl der Transaktionen auf dem Datenbankserver schreibt dieser die Logdateien also relativ häufig. Achten Sie daher beim Erstellen des archive_command darauf, keine »teuren« Befehle zu verwenden und die Logdateien z. B. aufwendig zu komprimieren oder zu verschlüsseln, denn 16 MB Logdatei sind bei einem gut frequentierten Datenbankserver schnell geschrieben, und entsprechend oft wird das archive_command ausgeführt. Verlagern Sie das Verarbeiten der Logdateien lieber in einen Backend-Prozess, und benutzen Sie archive_command nur, um die aktuelle Logdatei aus dem produktiv genutzten Verzeichnis zu verschieben.
Analog zur Direktive checkpoint_timeout (siehe Abschnitt »Optimierung« auf Seite 213) dient die Direktive archive_timeout dazu, Archiv-Logdateien in regelmäßigen Abständen zu schreiben, auch wenn keine oder nur wenige Transaktionen auf dem Datenbankserver ablaufen. Ein Wert von 60 (Sekunden) ist ein guter Mittelwert, je nach Last des Servers können Sie den Wert entsprechend anpassen. Nachdem Sie den Server durch Aktivieren des Archive-Mode in die Lage versetzt haben, Online-Sicherungen durchführen zu können, müssen Sie einmalig ein initiales Backup ausführen. Damit erstellen Sie die Ausgangsbasis, von der aus der Datenbankserver mit Hilfe der WAL-Logdateien jederzeit wieder in den letzten konsistenten Zustand gebracht werden kann. Das initiale Backup besteht aus dem Sichern der Datendateien, wobei dies im Online-Modus passieren kann – der Datenbankserver muss dazu nicht angehalten werden. Sie müssen dem Server lediglich vor und nach dem Kopieren durch entsprechende Befehle mitteilen, dass Sie ein Backup durchführen. Um das initiale Backup zu erzeugen, starten Sie das Programm psql als Benutzer postgres. Der postgres-Benutzer muss administrative Rechte auf dem Datenbankserver besitzen. Falls Sie dem Datenbankadministrator also einen anderen Benutzernamen zugewiesen haben, verwenden Sie bitte diesen Benutzer. Nach dem Start des Programms versetzen Sie den Datenbankserver mit dem folgenden Befehl in den Backup-Modus:
226
Datenbanken
select pg_start_backup('initial_backup');
Den in Klammern stehenden Bezeichner können Sie selbst wählen, er wird vom Datenbankserver als Label für das Backup verwendet. Der Datenbankserver sollte mit der folgenden Meldung antworten: pg_start_backup ----------------0/1D000020 (1 row)
Wichtig ist die letzte Zeile, (1 row). An dieser sehen Sie, dass der Befehl erfolgreich ausgeführt worden ist. Die Hexadezimalzahl in der vorletzten Zeile ist variabel und stellt lediglich einen Positionsmarker dar. Nach dem Absetzen des Befehls sollte im Postgres-Verzeichnis eine Datei backup_ label existieren, in der Informationen zum aktuellen Backup abgelegt sind: # cat /var/lib/postgresql/8.3/main/backup_label START WAL LOCATION: 0/1D000020 (file 00000001000000000000001D) CHECKPOINT LOCATION: 0/1D000020 START TIME: 2008-07-20 10:04:42 CEST LABEL: initial_backup
Nachdem der Datenbankserver die Ausführung des Befehls pg_start_backup abgeschlossen hat – was je nach Last des Servers einige Minuten dauern kann –, führen Sie ein Backup der Datendateien auf Dateisystem-Ebene durch. Das bedeutet ganz profan: Sichern Sie das gesamte PostgreSQL-Verzeichnis, unter Ubuntu /var/ lib/postgresql/8.3/main, unter Gentoo /var/lib/postgresql/data. # sudo cp –r <postgres_dir>
Wenn das Sichern der Dateien abgeschlossen ist, halten Sie den Backup-Modus des Datenbankservers über psql wieder an: foo=# select pg_stop_backup(); pg_stop_backup ---------------0/24000000 (1 row)
Auch hier gibt die letzte Zeile an, ob die Operation erfolgreich war. Eine mögliche Fehlermeldung wäre die folgende: foo=# select pg_stop_backup(); ERROR: a backup is not in progress
227
4.2
4
Serverdienste
Diese Fehlermeldung erscheint, wenn das Starten des Backup-Modus mit pg_ start_backup nicht erfolgreich war. Damit haben Sie den Datenbankserver für die Online-Sicherung konfiguriert. Mit dem initialen Datenbestand und den von jetzt an geschriebenen WAL-Logdateien kann der letzte konsistente Zustand der Datenbanken jederzeit wiederhergestellt werden. Das alte Backup-Dilemma Ein Backup nutzt relativ wenig, wenn die zu sichernden Daten nicht an einem sicheren Ort aufbewahrt werden. Wenn Sie die Online-Sicherung nur verwenden wollen, um die Datenbanken nach einem Absturz wiederherstellen zu können, ist das Ablegen der gesicherten Datendateien und der WAL-Logdateien auf einem lokalen Dateisystem ausreichend – gegen einen Festplattenschaden, Diebstahl des Servers, Brand im Serverraum, einen stolpernden Administrator mit Kaffeetasse in der Hand und ähnliche Fährnisse hilft das allerdings nicht. Daher sollten Sie beim Planen des Backups daran denken, die Backup-Daten an einem Ort zu sichern, der physikalisch vom Server getrennt ist. Zumindest aber sollten Sie in regelmäßigen Abständen die Backup-Daten auf ein externes Medium sichern und dieses Medium gut verwahren.
Für eine funktionierende Datensicherung ist ein Backup jedoch nur die halbe Miete. Genauso wichtig wie das korrekte Sichern der Daten ist es, die Daten im Bedarfsfall auch wiederherstellen zu können. Die Wiederherstellung der Daten aus der Online-Sicherung des PostgreSQL-Servers wird nachfolgend beschrieben. Als ersten Schritt müssen Sie den PostgreSQL-Server anhalten. Das sollte nicht weiter dramatisch sein, denn wenn Sie in der Situation sind, ein Backup zurückspielen zu müssen, kann es um den laufenden Datenbestand des Servers nicht gut bestellt sein. Anmerkung zum Restore Ein Restore der Datenbank aus den Daten der Online-Sicherung bedeutet immer, dass der gesamte Datenbestand des laufenden Datenbankservers durch den Datenbestand des Backups ersetzt wird. Ein selektiver Restore einzelner Daten ist nicht möglich. Um so etwas zu realisieren, müssten Sie händisch regelmäßig SQL-Dumps der laufenden Datenbank erzeugen und im Bedarfsfall aufwendig per Hand in die laufende Datenbank zurückdumpen – ein nicht zu empfehlendes Vorgehen.
Im nächsten Schritt verschieben Sie zunächst alle Datendateien des Servers aus den entsprechenden Verzeichnissen und dann die WAL-Logdateien aus dem pg_ xlog-Verzeichnis des Datenbankservers in ein temporäres Verzeichnis. Kopieren Sie danach die Datendateien des initialen Backups in die entsprechenden Verzeichnisse des Datenbankservers. Wichtig hierbei ist, dass die Dateiberechtigun-
228
Datenbanken
gen korrekt gesetzt sind, die Dateien und Verzeichnisse also dem Benutzer postgres und der Gruppe postgres gehören. Häufig werden Backuparbeiten als rootBenutzer ausgeführt, so dass die Dateiberechtigungen anschließend falsch sind und der Datenbankserver seinen Dienst quittiert. Falls WAL-Logdateien existieren, die nach dem letzten Backup und vor dem Systemabsturz bzw. dem Ereignis liegen, welches das Restore notwendig gemacht hat, kopieren Sie diese Logdateien in das pg_xlog-Verzeichnis des PostgreSQLServers. Analog zu der Direktive archive_command muss der Datenbankserver über die Direktive restore_command mitgeteilt bekommen, welchen Befehl er zum Wiederherstellen der Daten verwenden soll. Diese Direktive wird in der Datei recovery.conf verwendet, die extra für das Restore im Datenverzeichnis des Servers angelegt werden muss. In dieser Datei muss mindestens die besagte Direktive enthalten sein. Die Syntax ist dieselbe wie bei archive_command, nur dass Sie in diesem Fall einen Befehl zum Kopieren der archivierten WAL-Logdateien angeben müssen. Das bedeutet im simpelsten Fall einen Copy-Befehl, der die WALLogdateien aus dem Backup-Verzeichnis in das Logverzeichnis des Datenbankservers kopiert: restore_command = 'cp /%f %p'
Die Platzhalter %f und %p stehen dabei – wie bei archive_command – für den aktuellen Dateinamen (%f) und den gesamten Pfad der Datei (%p). Wichtige, optionale Direktiven für die Datei recovery.conf sind die folgenden: recovery_target_time: Legt den Zeitpunkt fest, bis zu dem die Sicherung durch-
laufen soll. Wenn Sie Transaktionen am Ende der Sicherung nicht zurücksichern möchten, geben Sie den entsprechenden Zeitpunkt an. Ob der angegebene Zeitpunkt auch zurückgesichert wird, hängt von der Direktive recovery_target_inclusive ab. recovery_target_xid: Legt die ID einer Transaktion fest, bis zu der zurückgesi-
chert werden soll. Wenn Sie z. B. eine Transaktion als Fehlerursache für einen Datenbankabsturz identifiziert haben, sichern Sie bis zur letzten Transaktion vor dieser und setzen den Betrieb dann von dort aus fort. Auch hier gibt die Direktive recovery_target_inclusive an, ob die angegebene Transaktions-ID in das Recovery mit eingeschlossen werden soll oder nicht. recovery_target_inclusive: Mit dieser Direktive, die den Wert true oder false annehmen kann, legen Sie fest, ob bei den beiden vorstehenden Direk-
tiven der angegebene Zeitpunkt oder die Transaktions-ID beim Recovery berücksichtigt werden soll oder nicht. Ist der Wert dieser Direktive false, läuft die Si-
229
4.2
4
Serverdienste
cherung nur bis zu dem mit recovery_target_time oder recovery_target_xid angegebenen Punkt. Ist der Wert true, stoppt das Recovery nach der Wiederherstellung der definierten Punkte. Nach dem Anlegen der Datei recovery.conf starten Sie den Datenbankserver, der dann mit dem Wiederherstellen der Daten aus den WAL-Logdateien beginnt. Je nach Datenmenge kann dieser Vorgang Sekunden, Minuten, Stunden oder Tage dauern. Sobald die Wiederherstellung der Daten abgeschlossen ist, benennt der Datenbankserver die Datei recovery.conf in recovery.done um. Vorsicht vor störenden Zugriffen Damit während des Backups kein Benutzer auf die Datenbank zugreifen kann, sollten Sie den Webserver bzw. alle Dienste, die schreibend auf die Datenbank zugreifen, anhalten, bevor Sie den Datenbankserver im Restore-Modus starten.
4.3
Apache Tomcat
Das Ausführen von PHP-Code oder CGI-Skripten in Webseiten lässt sich ohne Aufwand über den Apache-Server realisieren. Für PHP (und andere Sprachen) existieren Module, die in den Server einkompiliert werden können – die CGISchnittstelle erlaubt das Einbinden externer Programme, egal welcher Sprache. Mit dem Aufkommen von Java entstand relativ schnell die Anforderung, JavaCode auf dem Webserver ausführen zu können. Wurde Java in seiner Anfangszeit aus falsch verstandener Motivation in erster Linie in Java-Applets eingesetzt – also in Java-Programmen, die vom Client ausgeführt werden –, wandelte sich das Anwendungsgebiet mit der Zeit von der clientseitigen zur serverseitigen Verwendung von Java. Aus der Zeit der Java-Applets stammt auch noch das nicht totzukriegende Gerücht, Java sei per se langsam – was nicht verwundert, denn das Übertragen eines Java-Applets an den Client, das Starten der virtuellen Maschine auf dem Client-Rechner und das Laden des Java-Bytecodes in die virtuelle Maschine verbraucht eine Menge Zeit. Nichtsdestotrotz hat sich Java für den Endbenutzer weitestgehend unbemerkt im Serverbereich verbreitet, wo es für die Programmierung dynamischer Webapplikationen mit erhöhten Anforderungen an Datenpersistenz und ausgefeilten Programmiermöglichkeiten eine gute Plattform bietet. Java-Applikationen können allerdings nicht von Apache verarbeitet werden, dazu ist ein weiterer Serverdienst notwendig.
230
Apache Tomcat
Von der Apache Software Foundation, der Organisation, von der auch der Apache-Webserver stammt, gibt es dazu den Tomcat-Server, einen Application-Server zur Ausführung von Java-Programmen, so genannte Servlets, und JavaServer Pages (JSP). Der Tomcat-Server ist eine Weiterentwicklung der JServ-Technologie. Neben der Fähigkeit, Java-Code ausführen zu können, bringt der Tomcat-Server einen eigenen Webserver mit. Damit kann er im Standalone-Modus betrieben werden. Der eingebaute Webserver kann natürlich nicht mit der Funktionsvielfalt und der Performance des Apache-Webservers mithalten, so dass im Livebetrieb in der Regel ein Apache-Webserver als Frontend-Server eingesetzt wird, der alle Anfragen an Servlets oder JavaServer Pages an einen nachgelagert platzierten Tomcat-Server weiterleitet. Um diesen Aufbau zu realisieren, bringt der Tomcat ein eigenes Kommunikationsprotokoll mit, das Apache JServ Protokoll AJP. Für den Apache-Webserver steht das Modul mod_jk zur Verfügung, das über AJP mit einem Tomcat-Server kommunizieren kann. Im Zusammenhang mit Tomcat werden Sie unweigerlich auf die Begriffe Coyote und Catalina treffen. Coyote ist die Schnittstelle des Tomcat zu den Benutzern (HTTP) oder einem ApacheWebserver mit mod_jk-Modul (AJP). Catalina ist das eigentliche Kernstück des Tomcat, die Ausführungsschicht für Java-Servlets und JSPs.
4.3.1
Installation und Konfiguration
Die Installation unter Ubuntu ist gewohnt einfach. Unter Ubuntu 8.04 ist über das Paketmanagement der Tomcat-Server in der Version 5.5 erhältlich. # sudo apt-get install tomcat5.5 tomcat5.5-admin tomcat5.5-webapps
Wundern Sie sich nicht – apt wird eine ziemlich lange Liste von zusätzlichen Paketen installieren, hauptsächlich Java-Bibliotheken und Werkzeuge, Dinge, die der Tomcat benötigt. Netterweise startet apt den Tomcat nach der Installation automatisch und legt auch ein Init-Skript samt symbolischer Links für den automatischen Start an, so dass Sie direkt loslegen können. Erreichbar ist er im Browser auf Port 8180. Unter Gentoo wird der Tomcat wie gewohnt mit emerge installiert. Gentoo ist beim Tomcat schon weiter als Ubuntu und bietet (zum Zeitpunkt der Manuskripterstellung) die Version 6.0.16 an. Falls Sie eine JSP-basierte Website betreiben möchten, ist die Auswahl der richtigen Tomcat-Version möglicherweise ein wichtiges Argument für oder gegen eine der beiden Distributionen. # sudo emerge tomcat
231
4.3
4
Serverdienste
Abbildung 4.45
Die Tomcat-Startseite unter Ubuntu
Beispiele können hilfreich sein Wenn Sie bei der Installation des Tomcat unter Gentoo auch die zum Tomcat gehörenden Beispieldateien und -applikationen installiert haben möchten, müssen Sie das USEFlag examples setzen.
Auch hier ist die Installation umfangreich, planen Sie also lieber etwas Zeit ein. Nach Abschluss der Installation können Sie den Tomcat über sein Init-Skript starten: # sudo /etc/init.d/tomcat-6 start
Damit der Tomcat beim Systemstart automatisch geladen wird, müssen Sie mit rc-update noch die entsprechenden symbolischen Links erzeugen: # sudo rc-update add tomcat-6 default * tomcat-6 added to runlevel default
232
Apache Tomcat
4.3.2
»mod_jk« – Zusammenarbeit mit dem Webserver
Die ausschließliche Verwendung des Tomcat-eigenen Webservers kann eine sinnvolle Alternative zur Kombination aus Tomcat und Apache sein. Bei der Auslieferung statischer Inhalte kann der Tomcat durchaus mit der Performance eines Apache-Servers mithalten. In von Jason Brittain und Ian F. Darwin durchgeführten Benchmarks hat sich ergeben, dass der Tomcat-Webserver bei vielen Aufgabenstellungen sogar wesentlich performanter ist als ein Apache-Webserver. Beim Ausliefern statischer Inhalte hat der Tomcat gegenüber einem prefork-Apache die Nase weit voraus. Die besagten Benchmarks haben Werte von bis zu 136 % schnelleren Antwortzeiten des Tomcat gegenüber dem Apache ergeben! Ein worker-Apache sieht im Vergleich zum Tomcat schon besser aus, kann aber immer noch nicht mit dem Tomcat mithalten. Diese Benchmarks sind natürlich – wie alle Benchmarks – schwerlich als repräsentativ zu betrachten, da sie keine realen Bedingungen widerspiegeln, insbesondere was die Art und Größe der auszuliefernden Dateien angeht. Aufgrund des bemerkenswert großen Unterschiedes zwischen Apache und Tomcat ist die Grundaussage allerdings recht eindeutig. Dasselbe gilt für die Einbindung des Tomcat in den Apache über das Modul mod_ jk. Hier haben die Benchmarks von Brittain und Darwin einen Unterschied von bis zu 578 % ergeben, d. h., ein direkt angesprochener Tomcat liefert seine Daten – in diesem Fall keine statischen Daten, sondern JSPs oder Servlets – 578 % schneller aus als ein über mod_jk angesprochener Tomcat. Die Tests wurden nicht mit Daten durchgeführt, wie sie auf einem Livesystem zum Einsatz kommen, aber auch hier ist die Sachlage eindeutig. Eine mögliche Erklärung für diese Unterschiede in der Peformance kann sein, dass der Tomcat, der komplett in Java programmiert ist, extrem von den HotspotOptimierungsmöglichkeiten der virtuellen Maschine profitiert. Dabei sucht der Just-In-Time-Compiler der VM zur Laufzeit nach Optimierungsmöglichkeiten, übersetzt optmimierungsfähige Codeabschnitte in Maschinensprache und erzielt so eine ideale Optimierung. Der Apache-Webserver dagegen ist in C geschrieben, so dass sämtliche Optimierungsmöglichkeiten nur zur Übersetzungszeit gegeben sind, was die nachträgliche Anpassung an die tatsächlichen Gegebenheiten unmöglich macht. Nichtsdestotrotz gibt es gute Gründe, den Tomcat nicht als Frontendserver zu verwenden. Der erste und gewichtigste Grund ist, dass die Konfiguration des Tomcat aufgrund der XML-Syntax alles andere als intuitiv ist. Böse Zungen würden die Konfiguration sogar als ausgesprochen undurchsichtig und unzeitgemäß bezeichnen. Darüber hinaus gibt es ein rein praktisches Problem beim Einsatz des Tomcat als Webserver. Ein Webserver lauscht standardmäßig auf Port 80, einem privilegierten Port. Um sich an einen privilegierten Port zu binden, muss ein
233
4.3
4
Serverdienste
Dienst mit Root-Rechten gestartet werden. Der Tomcat-Server läuft allerdings nicht mit Root-Rechten, sondern mit den Rechten eines normalen Benutzers – zumindest in der Standardkonfiguration –, und aus Sicherheitsgründen sollten Sie diese Einstellung nicht ändern, denn im Gegensatz zum Apache kennt der Tomcat das Prinzip nicht, mit Root-Rechten zu starten, um einen privilegierten Port benutzen zu können und dann alle weiteren Prozesse mit weniger privilegierten Rechten zu erzeugen. Sie müssen daher, wenn Sie den Tomcat als Webserver auf Port 80 verwenden wollen, entweder mit iptables über eine Port-Weiterleitung alle eingehenden Anfragen auf Port 80 an den Tomcat-Port weiterleiten oder durch ein vorgeschaltetes System wie z. B. einen Loadbalancer die Anfragen schon vor dem Server von Port 80 auf den Tomcat-Port umleiten. Dabei sollten Sie bedenken, dass der Tomcat als Webserver nur eine sehr eingeschränkte Funktionalität bietet und eine Vielzahl der Möglichkeiten des Apache über den Tomcat nicht abgebildet werden können. Im Sinne einer zukunftssicheren Installation sollten Sie daher für NichtJava-Webinhalte immer den Apache bevorzugen, denn damit haben Sie umfangreiche Möglichkeiten Module und Funktionalität einzubinden. Eine nachträgliche Migration einer Webapplikation von einem Tomcat auf einen Apache ist immer mit sehr viel Arbeit und Anpassung verbunden – Arbeit, die Sie sich sparen können. Ein gut optimierter Apache ist ein leistungsfähiger Server, und auch wenn der Tomcat »im Labor« sehr viel leistungsfähiger ist, wiegt die höhere Performance die Flexibilität und Zukunftssicherheit des Apache nicht auf. Daher ist es eine gute Idee, den Tomcat durch den Apache-Webserver anzusprechen. Der Apache fungiert in dieser Konstellation als Frontendserver und nimmt alle eingehenden Anfragen entgegen. Erhält er Anfragen, die an den Tomcat-Server gerichtet sind, leitet er diese durch das Modul mod_jk an den Tomcat weiter, der die Anfragen verarbeitet und das Ergebnis an den Apache zurückgibt, der sie dann wiederum an den Benutzer ausliefert. mod_jk gibt es als installierbares Paket für Ubuntu ... # sudo apt-get install libapache2-mod-jk
... und Gentoo: # sudo emerge mod_jk
Nach Abschluss der Installation ist Handarbeit angesagt. »mod_jk« unter Ubuntu Der Tomcat-Server verfügt praktischerweise über ein Auto-Konfigurationsfeature, mit dem sich eine rudimentäre Konfigurationsdatei für den Apache-Server
234
Apache Tomcat
erstellen lässt. Nach Abschluss der Installation suchen Sie dazu in der Datei /etc/ tomcat5.5/server.xml den Eintrag <Engine name="Catalina" defaultHost="localhost">. In den Engine-Abschnitt fügen Sie die folgende Zeile ein:
Der Pfad zum Modul mod_jk muss dem tatsächlichen Pfad entsprechen. Wenn Sie das Modul mit apt installiert haben, ist der vorstehende Pfad korrekt. Nach dem Neustart des Tomcat befindet sich im Verzeichnis /etc/tomcat5.5/auto die Datei mod_jk.conf mit dem folgenden Inhalt: ######## Auto generated on Tue Jul 12 22:45:34 GMT+02:00 2008####### LoadModule jk_module "/usr/lib/apache2/modules/mod_jk.so" ServerName localhost JkMount /servlets-examples ajp13 JkMount /servlets-examples/* ajp13 JkMount /webdav ajp13 JkMount /webdav/* ajp13 JkMount /admin ajp13 JkMount /admin/* ajp13 JkMount /host-manager ajp13 JkMount /host-manager/* ajp13 JkMount /jsp-examples ajp13 JkMount /jsp-examples/* ajp13 JkMount /tomcat-docs ajp13 JkMount /tomcat-docs/* ajp13 JkMount /manager ajp13 JkMount /manager/* ajp13 JkMount /balancer ajp13 JkMount /balancer/* ajp13
Kopieren Sie die Datei in das Verzeichnis /etc/apache2, und kommentieren Sie anschließend die Listener-Direktive in der Datei /etc/tomcat5.5/server.xml wieder aus, damit der Tomcat-Server nicht bei jedem Start eine Konfigurationsdatei für den Apache anlegt. Die JkMount-Direktiven legen die Verzeichnisse fest, die der Apache zur weiteren Bearbeitung an den Tomcat weiterreicht, sobald eins der entsprechenden Muster in der Anfrage eines Clients auftaucht. Die Zeichenkette ajp13 am Ende jeder JkMount-Zeile bezeichnet den Worker des Tomcat, an den der Apache die Anfragen
235
4.3
4
Serverdienste
sendet. ajp13 ist – nebenbei bemerkt – der Name des Protokolls10, über das Apache und Tomcat miteinander kommunizieren. Es steht für Apache JServ Protocol Version 1.3. Worker Ein Worker ist eine Instanz des Tomcat, die für die Bearbeitung eingehender Verbindungen zuständig ist, vergleichbar einem virtuellen Server beim Apache. Worker werden über die in der nachfolgend beschriebenen Direktive JkWorkersFile festgelegte Datei konfiguriert. Das Modul mod_jk bringt eine Beispieldatei mit, die für den Anfang vollkommen ausreichend ist, da sie einen funktionierenden Standard-Worker beschreibt.
In der neu erzeugten Datei /etc/apache2/mod_jk.conf kommentieren Sie die VirtualHost-Direktiven und die Direktive ServerName aus. Wenn Sie für die Tom-
cat-Anbindung einen eigenen virtuellen Server verwenden möchten, können Sie die VirtualHost-Direktiven belassen, müssen diese aber Ihren Anforderungen entsprechend konfigurieren. Fügen Sie anschließend noch die folgenden drei Zeilen in die Datei ein. JkWorkersFile "/etc/libapache2-mod-jk/workers.properties" JkLogFile "/var/log/apache2/mod_jk.log" JkLogLevel debug
Mit der ersten Direktive legen Sie einen Verweis auf die Worker-Datei an, mit der zweiten definieren Sie eine Logdatei, in der alle Aktionen des Moduls mod_jk geloggt werden, und mit der dritten Direktive legen Sie den Loglevel für diese Datei fest. Während der Einrichtung und im Testbetrieb ist debug ein guter Wert, weil der Apache dann sehr ausführlich loggt. Im Produktivbetrieb belastet das den Server allerdings zu stark und sollte auf error oder notice zurückgesetzt werden, um nur Fehler oder wichtige Meldungen in die Logdatei schreiben zu lassen. Die Datei /etc/libapache2-mod-jk/workers.properties enthält die folgenden Direktiven: workers.tomcat_home=/usr/share/tomcat5.5 workers.java_home=/usr/lib/jvm/java-gcj ps=/ worker.list=ajp13_worker worker.ajp13_worker.port=8009 worker.ajp13_worker.host=localhost worker.ajp13_worker.type=ajp13 worker.ajp13_worker.lbfactor=1 worker.loadbalancer.type=lb worker.loadbalancer.balance_workers=ajp13_worker 10 http://tomcat.apache.org/connectors-doc/ajp/ajpv13a.html
236
Apache Tomcat
Da die vom Tomcat erzeugte Konfigurationsdatei den Worker ajp13 verwendet, müssen Sie in der Datei /etc/libapache2-mod-jk/workers.properties den Namen des definierten Workers von ajp13_worker auf ajp13 ändern. Um die Konfiguration des Webservers zentral zu halten, kopieren Sie die Datei in das Verzeichnis /etc/apache2 und ändern dort ajp13_worker in ajp13. Wenn Sie sich das händische Ändern sparen wollen, lassen Sie sich von sed helfen: # sudo cat /etc/libapache2-mod-jk/workers.properties | sed ' s/ ajp13_worker/ajp13/' > /etc/apache2/workers.properties
Anschließend passen Sie in der Datei /etc/apache2/mod_jk.conf noch in der Direktive JkWorkersFile den Pfad an … JkWorkersFile "/etc/apache2/workers.properties"
… und starten den Apache neu: # sudo /etc/init.d/apache2 restart
Wenn Sie nun über den Apache die Beispielseiten des Tomcat aufrufen, werden Sie eine korrekte Antwort erhalten – vom Tomcat, der diese Anfrage durch den Apache bedient.
Abbildung 4.46
Tomcat über mod_jk unter Ubuntu
237
4.3
4
Serverdienste
»mod_jk« unter Gentoo Das Modul mod_jk können Sie unter Gentoo mit dem Befehl … # sudo emerge mod_jk
… installieren. Unter Gentoo ist nach der Installation nur eine Änderung in der Datei /etc/conf.d/apache2 notwendig, um das Modul mod_jk zu laden. Fügen Sie in dieser Datei zur Zeile APACHE2_OPT="..." den Wert -D JK an, um das Modul mod_jk beim Start des Apache zu laden: APACHE2_OPTS="-D DEFAULT_VHOST -D INFO -D LANGUAGE -D SSL -D SSL_ DEFAULT_VHOST -D PHP5 -D JK"
Anschließend starten Sie den Apache neu und rufen eine beliebige Datei mit der Endung .jsp auf. Da in der Konfiguration von mod_jk in der Datei /etc/apache2/ modules.d/88_mod_jk.conf ein JkMount auf alle Dateien mit der Endung .jsp definiert ist (JkMount /*.jsp ajp13), kommt die Fehlermeldung, dass die angeforderte Datei nicht vorhanden ist, vom Tomcat und nicht vom Apache (Abbildung 4.47).
Abbildung 4.47
Tomcat mit mod_jk unter Gentoo
Wenn Sie mehr als eine Fehlermeldung vom Tomcat erhalten möchten, definieren Sie in der Datei /etc/apache2/modules.d/88_mod_jk.conf ein JkMount auf das Verzeichnis /examples des Tomcat, in dem sich Beispieldateien befinden. Dazu fügen Sie nach der ersten JkMount-Direktive einfach die folgende Zeile in die Datei ein und starten den Apache anschließend neu: JkMount /examples/* ajp13
238
Apache Tomcat
Damit ist dann auch der Zugriff auf die Beispielprojekte des Tomcat möglich (Abbildung 4.48). Festlegen von JkMounts Genauso einfach wie der Zugriff auf die Beispieldateien des Tomcat lassen sich Ihre eigenen Verzeichnisse mit den vom Tomcat auszuliefernden Daten konfigurieren. Definieren Sie in der Konfiguration des Moduls mod_jk über JkMount-Direktiven die Verzeichnisse und/oder Dateien, die der Tomcat ausliefern soll. Am Tomcat selbst müssen Sie für die Verbindung mit dem Apache nichts ändern.
Abbildung 4.48
4.3.3
Zugriff auf die Tomcat-Beispiele über mod_jk
Grundlegende Absicherung
Der Tomcat-Server ist reines Java und dementsprechend sind Konfiguration und Sicherheitsmodell des Servers und der darauf laufenden Applikationen ganz oder zumindest stark an die Sicherheitsmechanismen der virtuellen Java-Maschine angelehnt. Ohne in die Java-Programmierung einzusteigen – es gibt zwei Schritte, die Sie nach der Installation des Tomcat durchführen sollten, um den Server zu härten. Der erste Schritt ist das Entfernen aller Beispieldateien und der Tomcat-Administrator-Oberfläche – sofern vorhanden. Wie beim Apache weisen auch beim Tomcat Standarddateien und -verzeichnisse einen Angreifer schnell darauf hin, dass der Server nicht ausreichend gehärtet ist. Die Tomcat-Administrator-Oberfläche, erreichbar über die Verzeichnisse /admin und /manager, sollten Sie gar nicht erst installieren. Für Einsteiger scheint die Konfiguration des Tomcat über diese Ober-
239
4.3
4
Serverdienste
fläche zwar ganz angenehm, aber sie führt dazu, dass die Konfigurationsdatei des Tomcat (server.xml) für einen Menschen unlesbar wird, da sie alle Kommentare und Leerzeilen entfernt und eine eigene Formatierung verwendet. Darüber hinaus ist die Admin-Oberfläche immer wieder Ziel von Angreifern, die über einen vergessenen Zugang mit den Standardzugangsdaten (Benutzer tomcat mit Passwort tomcat) administrativen Zugriff auf den Tomcat-Server erhalten. Beim Entfernen von nicht benötigten Dateien und Verzeichnissen sollten Sie nicht nur die entsprechenden JkMounts in der Apache-Konfiguration entfernen, sondern die Dateien und Verzeichnisse komplett von der Festplatte löschen, um eine versehentliche Reaktivierung auszuschließen. Im zweiten Schritt der Härtung sperren Sie den Netzwerkzugriff auf die verschiedenen TCP-Ports, die der Tomcat öffnet. Soll Ihr Tomcat nur über den ApacheWebserver angesprochen werden, sollten Sie die Ports 8009 (ajp13), 8080 oder 8180 (HTTP) und 8443 (HTTPS) über iptables für den Zugriff über das Netzwerk sperren. So stellen Sie sicher, dass der Tomcat nur noch über den Apache angesprochen werden kann. Die entsprechenden Befehle dazu sind die folgenden – bauen Sie sie einfach in Ihr Firewall-Skript ein: iptables iptables iptables iptables
–A –A –A –A
INPUT INPUT INPUT INPUT
–p –p –p –p
tcp tcp tcp tcp
–dport –dport –dport –dport
8009 8080 8180 8443
–j –j –j –j
DROP DROP DROP DROP
Unter Ubuntu lauscht der Tomcat für eingehende HTTP-Verbindungen auf Port 8180, unter Gentoo auf Port 8080, was auch dem Tomcat-Standard entspricht.
4.4
Jabber
Der Webserver ist eingerichtet, die Website läuft, die Benutzer tummeln sich auf der Website. Wenn Sie nicht nur eine statische Website anbieten, sondern eine Community oder ein Forum betreiben, darf es irgendwann sicher etwas mehr sein als nur webbasierte Kommunikation. Auch wenn das Web immer mehr Internetdienste kannibalisiert, gibt es doch einige Dienste, die sich hartnäckig dagegen sträuben, ins WWW zu wandern. Chat ist ein solcher Dienst. Trotz einer Vielzahl webbasierter Chat-Plattformen gibt es noch immer das althergebrachte IRC, vielen nur als Befehlsstand für Bot-Netze bekannt. IRC ist allerdings nicht nur althergebracht, sondern auch altbacken. Plattformen wie ICQ, AIM, der Microsoft Messenger und Skype haben die Ansprüche an eine Chat-Plattform massiv steigen lassen, und so wundert es nicht, das sich in den letzten Jahren eine Chat-Plattform auf Open-Source-Basis entwickelt hat, die mit den Annehmlich-
240
Jabber
keiten der kommerziellen locker mithalten kann, dabei aber nicht deren Einschränkungen unterliegt. Skype, ICQ und Konsorten sind zwar sehr schön in Aussehen und Bedienung, haben aber den eklatanten Nachteil, dass jegliche ChatKommunikation immer über zentrale Server der jeweiligen Anbieter läuft. Der Telekom-Abhörskandal hat gezeigt, dass man noch nicht einmal Unternehmen vertrauen kann, die allgemein als vertrauenswürdig gelten, dem deutschen Telekommunikations- und Datenschutzrecht unterliegen und obendrein im Internet »hoheitliche« Aufgaben innehaben und als Certification Authority (CA) für das Ausstellen und Signieren von Zertifikaten zuständig sind. Da ist es schon eher wagemutig, seine private Chat-Kommunikation über Server amerikanischer Firmen laufen zu lassen, zumal im Fall von ICQ die Nutzungsbedingungen11 sehr genau gelesen werden sollten: »You agree that by posting any material or information anywhere on the ICQ Services and Information you surrender your copyright and any other proprietary right in the posted material or information. You further agree that ICQ LLC. is entitled to use at its own discretion any of the posted material or information in any manner it deems fit, including, but not limited to, publishing the material or distributing it.« Sie treten für alle Informationen, die Sie über das ICQ-Netzwerk austauschen – also Ihre Chat-Gespräche – das Urheberrecht an ICQ ab. ICQ darf mit den Informationen machen, was es will, inklusive Veröffentlichung und weitere Verarbeitung zu nicht näher definierten Zwecken. Während Firmen wie Skype, Microsoft, Yahoo oder Google sich zumindest den Anschein geben, mit den Daten ihrer Nutzer sorgsam umzugehen – überprüfen kann man es ohnehin nicht – ist diese Klausel in den Nutzungsbedingungen von ICQ ein Freibrief für den Anbieter, die Daten seiner Benutzer zu missbrauchen. Vom Aspekt der Datensicherheit abgesehen, erfordern die kommerziellen ChatPlattformen immer auch die Installation proprietärer Chat-Software. Es gibt zwar für einige Plattformen Alternativen, aber gerade ICQ hat sich in der Vergangenheit immer wieder durch Änderungen des – ebenfalls proprietären – Chat-Protokolls hervorgetan und so alternative Chat-Clients mit schöner Regelmäßigkeit ausgeschlossen. Geschlossene Systeme sind eben selten ein Garant für Benutzerfreundlichkeit. Glücklicherweise gibt es eine Alternative auf Open-Source-Basis, das Jabber-Protokoll. Jabber ist der englische Begriff für quasseln oder quatschen, eine sehr passende Bezeichnung für einen Chat-Dienst. Das Jabber-Chat-Protokoll bietet alle Merkmale moderner Chat-Dienste, wie z. B. Statusanzeige, Gruppenchats, Daten11 http://www.icq.com/legal/policy.html
241
4.4
4
Serverdienste
übertragung etc. Das Protokoll ist ein offener Standard (zumindest das Kernstück XMPP), für den es verschiedene Client- und Server-Implementierungen für alle gängigen Betriebssysteme gibt, auch und insbesondere für Linux. Für private Communities oder Firmen ergibt sich daraus die Möglichkeit, kostengünstig eine Instant-Messaging-Plattform aufzubauen und zu betreiben, ohne dass dafür proprietäre und geschlossene Software verwendet oder Verbindungen zu Servern bestimmter Anbieter aufgebaut werden müssen. Jabber kann (und sollte) über SSL betrieben werden, so dass die Kommunikation zwischen den Clients und dem Jabber-Server verschlüsselt abläuft. Darüber hinaus bieten die verschiedenen Jabber-Clients auch verschiedene Formen der Endto-End-Verschlüsselung an, einige stellen Verschlüsselung per GPG zur Verfügung, andere haben bereits die moderne Off-the-Records-Verschlüsselung (OTR) implementiert. Mit der SSL-Verschlüsselung schützen Sie die Chat-Benutzer vor Mithören auf der Strecke zwischen Client und Server. Mit End-to-End-Verschlüsselung schützen sich die Benutzer vor Mithören auf der Leitung und auf dem Server. Wenn Ihre Benutzer also End-to-End-Verschlüsselung verwenden, können Sie auf dem Jabber-Server die Kommunikation Ihrer Benutzer nicht mitlesen. In diesem Fall bietet Jabber ein absolut vertrauliches Kommunikationsmedium. Jabber-Server können untereinander zu einem Netzwerk verbunden werden. Das Jabber-Protokoll sieht hierfür eine Identifizierung von Benutzern ähnlich wie bei E-Mail vor: [email protected] (tld steht dabei für Top-Level-Domain). Darüber hinaus gibt es Übergänge, so genannte Transporte, zu anderen Messenger-Diensten (ICQ, IRC, MSN, AIM etc.). Diese Übergänge werden serverseitig realisiert, d. h., für den Benutzer ist – bis auf die Benutzerkennung des Gesprächspartners – das vom Gesprächspartner genutzte Chat-System transparent. Die Entwicklung des Jabber-Protokolls wird von der XMPP Standards Foundation (XFS), ehemals Jabber Software Foundation, betrieben. Auf der Website der XFS12 finden Sie umfangreiche Informationen zum Jabber-Protokoll und Listen zu Jabber-Software, -Server und -Clients. Ein weitverbreiteter Jabber-Server ist der Ejabberd. Dieser Server steht unter der GPL – ist somit Open Source – und ist für verschiedene Plattformen verfügbar: Linux, OS X, Windows, AIX, BSD, HP-Unix und Solaris. Für Ubuntu und Gentoo gibt es fertige Pakete, so dass der Ejabberd komfortabel über die Paketmanager beider Distributionen installiert werden kann. Eine Besonderheit vom Ejabberd ist die Programmiersprache, in welcher der Dienst geschrieben ist. Der Autor hat die Sprache Erlang gewählt, die aus der Telefonwelt kommt und ursprünglich zur Programmierung von Software für Vermittlungsstellen verwendet wurde. Von 12 http://www.jabber.org/
242
Jabber
daher sollten Sie nicht verzweifeln, wenn Sie beim Blick in den Sourcecode von Ejabberd kein Wort verstehen.
4.4.1
Installation unter Ubuntu
Unter Ubuntu installieren Sie den Ejabberd mit dem folgenden Befehl: # sudo apt-get install ejabberd
Um den Dienst unter Ubuntu erstmalig zu konfigurieren, rufen Sie nach der Installation dpkg-reconfigure aus: # sudo dpkg-reconfigure ejabberd
Im ersten Schritt des Dialogs müssen Sie den Namen Ihres Jabber-Servers eingeben. Dieser besteht wie der kanonische Name eines Webservers aus einem echten Domainnamen – sofern vorhanden (Abbildung 4.49). Achten Sie darauf, dass bei der Verwendung von SSL zur Absicherung der Kommunikation zwischen Client und Server das SSL-Zertifikat auf den Namen des Servers ausgestellt wird. Ansonsten werden die Clients bei jeder Verbindung eine Fehlermeldung ausgeben, dass Servername und der im Zertifikat hinterlegte Name nicht übereinstimmen.
Abbildung 4.49
Name des Jabber-Servers
Im nächsten Schritt müssen Sie einen Administrator-Benutzer anlegen (Abbildung 4.50). Die Administration des Jabber-Servers erfolgt zum einen auf traditionellem Weg über eine Konfigurationsdatei, zum anderen kann der an dieser Stelle angelegte Administrator über seinen Jabber-Client und über die Weboberfläche des Ejabberd administrative Aufgaben durchführen. Nach Eingeben des
243
4.4
4
Serverdienste
Namens müssen Sie zweimal das Passwort des Administrator-Benutzers eingeben, danach ist die Konfiguration des Ejabberd abgeschlossen.
Abbildung 4.50
Anlegen des Jabber-Administrators
dpkg-reconfigure passt anschließend die Konfigurationsdatei /etc/ejabberd/
ejabberd.cfg an und startet den Ejabberd-Daemon neu: # dpkg-reconfigure ejabberd The ejabberd database has been backed up to /var/backups/ejabberd2008-07-25T20:57:57.Ln7141/ejabberd-database. Stopping jabber server: ejabberd. Replacing config file /etc/ejabberd/ejabberd.cfg with new version Starting jabber server: ejabberd. Waiting for ejabberd to register admin user.. Admin user "[email protected]" is registered successfully.
Damit ist die Installation unter Ubuntu bereits fertig. Der Ejabberd bringt eine webbasierte Administrationsoberfläche mit, die sich allerdings hinsichtlich der Nützlichkeit und Bedienbarkeit noch im pre-Alpha-Stadium befindet. Erreichen können Sie die Oberfläche auf Port 5280 im Verzeichnis /admin (Abbildung 4.51). Die Zugangsdaten sind der Benutzername des Jabber-Administrators und das dazugehörige Kennwort. Der Benutzername setzt sich wie eine E-MailAdresse aus dem eigentlichen Benutzernamen, dem Servernamen, der Domain und der Top-Level-Domain zusammen, also z. B. [email protected]. In Ihrem Fall besteht der Name aus den Angaben, die Sie bei der Konfiguration des Ejabberd-Paketes gemacht haben.
244
Jabber
Abbildung 4.51
Die Administrationsoberfläche des Ejabberd
Da die Oberfläche höchstens zur Verwirrung beiträgt und keine echte Hilfe ist, sollte sie in der Konfigurationsdatei des Servers deaktiviert werden. Öffnen Sie dazu die Datei /etc/ejabberd/ejabberd.cfg in einem Editor Ihrer Wahl und suchen Sie nach dem String 5280: {5280, ejabberd_http,
[http_poll, web_admin]}
Lassen Sie sich von der seltsamen Syntax der Konfigurationsdatei nicht verwirren – das ist Erlang-Syntax. Kommentieren Sie die vorstehende Zeile mit einem Prozentzeichen aus. Da dieser Eintrag einer von vielen in einem kommaseparierten Array ist, müssen Sie noch ein Komma entfernen, damit der Ejabberd beim Start nicht über eine ungültige Konfigurationsdatei stolpert. Die Port-Angabe für die Administrationsoberfläche ist Bestandteil der Direktive listen. Diese beginnt mit dem Schlüsselwort listen und enthält verschiedene Einträge, die jeweils in eckige Klammern gefasst und durch Kommata separiert sind. Die gesamte aktive listen-Direktive in der Ejabberd-Konfiguration unter Ubuntu 8.04 umfasst die folgenden Einträge: 1: {listen, 2: [{5222, ejabberd_c2s, 3: 4: 5: 6: 7: {5223, ejabberd_c2s, 8:
Um die Administrationsoberfläche zu deaktivieren, kommentieren Sie die vorstehend als Zeile 14 gekennzeichnete Zeile in der Konfigurationsdatei aus. Um der Semantik der Konfigurationsdatei Genüge zu tun, müssen Sie dann noch in der vorstehend als Zeile 13 bezeichneten Zeile das abschließende Komma entfernen, da hinter diesem Element kein weiteres Element mehr in der listen-Direktive folgt. Im gleichen Zug können Sie im Rahmen einer Serverhärtung auch weitere nicht benötigte Ports schließen. Zwingen Sie Ihre Benutzer zu ihrem Glück, und erlauben Sie nur SSL-Verbindungen. Den Server-2-Server-Service benötigen Sie lediglich, wenn Sie Ihren Jabber-Server mit anderen Jabber-Servern verbinden möchten. Sofern das nicht geplant ist, kommentieren Sie die entsprechenden Zeilen in der Konfigurationsdatei einfach aus. Für die Verbindung ohne SSL sind das die vorstehend als Zeilen 2–6 gekennzeichneten Zeilen. Den Server-2-Server-Service können Sie durch Auskommentieren der Zeilen 12 und 13 deaktivieren. In Zeile 7 muss dann noch eine öffnende eckige Klammer an den Zeilenanfang. Die gesamte listen-Direktive sieht anschließend wie folgt aus: {listen, {5223, ejabberd_c2s, [{access, c2s}, {max_stanza_ size, 65536}, tls, {certfile, "/etc/ejabberd/ ejabberd.pem"}, {shaper, c2s_shaper}]}]}.
Starten Sie den Ejabberd anschließend neu: # sudo /etc/init.d/ejabberd restart
Bei der Installation sind bereits die notwendigen symbolischen Links angelegt worden, so dass der Ejabberd beim Systemstart automatisch gestartet wird. Sie können nun einen beliebigen Jabber-Client mit dem Jabber-Server verbinden. Verwenden Sie das Konto kr, sind Sie als Jabber-Administrator eingeloggt. Alle anderen Benutzer können sich über ihren Jabber-Client ein neues Konto auf dem Jabber-Server anlegen.
246
Jabber
4.4.2
Installation unter Gentoo
Beim Ejabberd-Paket von Gentoo offenbart sich eine Schwäche von Gentoo: Das Paket ist schon länger als nur eingeschränkt brauchbar bekannt, leider ändert sich an diesem Status nichts. Zum Zeitpunkt der Manuskripterstellung ist das Paket so gut wie unbrauchbar. Glücklicherweise gibt es auf der Website von Process One, der Firma, die den Ejabberd pflegt, eine Binärversion zum Download13, die – mit einem sehr guten Installer ausgestattet – eine schnelle Inbetriebnahme der Version 2 des Ejabberd ermöglicht. Dort ist auch der Sourcecode erhältlich – je nach Geschmack können Sie den Ejabberd also auch selbst übersetzen. So oder so: Beim Einsatz von Fremdpaketen müssen Sie die Pflege der Pakete selbst in die Hand nehmen, die distributionseigene Paketverwaltung hilft dabei nicht. Im Folgenden wird die Installation des Binärpaketes erklärt. Laden Sie zunächst das Binärarchiv auf Ihren Linux-Server. Das können Sie auf einem Umweg über Ihren Client tun oder direkt vom Server aus. Im letzteren Fall verwenden Sie wget oder curl und übergeben dem Programm die Adresse der herunterzuladenden Datei auf dem Server von Process One. Das Installationsprogramm ist mit gzip gepackt, also müssen Sie es zunächst mit gzip entpacken: # gzip -d ejabberd-2.0.1_2-linux-x86-installer.bin.gz
Sofern Sie Ihr System nach den Vorgaben aus Kapitel 3, »Systemhärtung«, gehärtet haben, sollten die Dateirechte des Installers auf 600 stehen. Da es sich dabei aber um eine ausführbare Datei handelt, müssen Sie für den Eigentümer das x-Bit setzen: # chmod 700 ejabberd-2.0.1_2-linux-x86-installer.bin
Anschließend können Sie die Datei ausführen. Damit der Ejabberd in ein allgemein zugängliches Verzeichnis installiert werden kann, muss das Installationsprogramm mit Root-Rechten ausgeführt werden. Die meisten Einstellungen können auf den Vorgaben verbleiben. Das vorgeschlagene Installationsverzeichnis unterhalb von /opt entspricht den Vorgaben des FHS (siehe Kapitel 3, »Systemhärtung«) und kann beibehalten werden. # sudo ./ejabberd-2.0.1_2-linux-x86-installer.bin sudo: Language Selection Please select the installation language [1] German [2] English [3] Spanish
[4] French [5] Dutch [6] Russian [7] Simplified Chinese Please choose an option [2] : 1 ----------------------------------------------------------------Willkommen beim ejabberd Setup Assistenten ----------------------------------------------------------------Bitte lesen Sie die folgende Lizenzvereinbarung. Sie müssen dem Inhalt dieser Vereinbarung zustimmen, bevor Sie mit der Installation fortfahren können. Drücken Sie [Eingabe] um fortzufahren : [...] Akzeptieren Sie diese Lizenzvereinbarung? [y/n]: y ----------------------------------------------------------------Bitte geben Sie das Verzeichnis an, in dem Sie ejabberd installieren wollen. Installationsverzeichnis [/opt/ejabberd-2.0.1]: ----------------------------------------------------------------ejabberd Server Domäne Bitte geben sie den Domainnamen ein. Der Domainname ist ein sichtbares Attribut, welches zu jedem Benutzernamen hinzugefügt wird, um eine korrekte Jabber ID zu erstellen (zum Beispiel: [email protected]). Dieser Computer muß auch im Netzwerk unter diesem Namen bekannt sein. ejabberd Server Domäne [gentoo.localdomain]: jabber.rodewig.de ----------------------------------------------------------------Benutzername des Administrators Geben Sie bitte den Benutzernamen des Administrators für diese ejabberd Installation ein. Mit diesem Namen wird ein Jabber Konto angelegt und es erhält Administratorrechte. Bitte benutzen Sie keine Leerzeichen im Benutzernamen. Benutzername des Administrators [admin]: kr ----------------------------------------------------------------Administrator Passwort Bitte geben sie ein Passwort für den Adminstrator ein (mindestens 5 Zeichen). Administrator Passwort : ******** Passwort wiederholen : ******* ----------------------------------------------------------------Cluster Wird dieser Knoten Teil eines Clusters ? (Hinweis: ejabberd clustering wird nur für erfahrene Benutzer empfohlen). Cluster [y/N]: n
248
Jabber
----------------------------------------------------------------Das Setup ist jetzt vorbereitet, um ejabberd auf Ihrem Computer zu installieren. Wollen Sie fortfahren? [Y/n]: y ----------------------------------------------------------------Bitte warten Sie, während das Setup ejabberd auf Ihrem Computer installiert. Installiere 0 % ______________ 50 % ______________ 100 % ######################################### ----------------------------------------------------------------Das Setup hat die Installation von ejabberd auf Ihrem Computer beendet. Wollen Sie die LiesMich Datei anzeigen? [Y/n]: n
Nach Abschluss der Installation befinden sich unterhalb des während der Installation angegebenen Verzeichnisses alle Dateien des Ejabberd. Die Konfiguration entspricht der von Ejabberd in Version 1.4, unterscheidet sich also nicht von der unter Ubuntu. Die Konfigurationsdatei liegt im Verzeichnis conf/ unterhalb des Installationsverzeichnisses, bei der Standardinstallation also /opt/ejabberd-2.x/ conf/ejabberd.cfg. Standardmäßig sind die Verbindungen über Port 5222, der Server-2-Server-Service auf Port 5269 und die Administrationsoberfläche auf Port 5280 aktiviert. Passen Sie diese Einstellung Ihren Anforderungen an. Das Vorgehen hierbei entspricht dem Vorgehen unter Ubuntu, beschrieben in Abschnitt 4.4.1. Nach der Installation ist noch etwas Handarbeit angesagt. Zunächst müssen Sie eine Gruppe und einen Benutzer anlegen, mit dessen Rechten der Ejabberd laufen wird. Das mitgelieferte Startskript prüft auf den Benutzernamen ejabberd, daher müssen Sie einen gleichnamigen Benutzer anlegen. Der Übersichtlichkeit halber nennen Sie die Gruppe auch ejabberd. Als Home-Verzeichnis des Benutzers können Sie das Installationsverzeichnis des Ejabberd angeben. # sudo groupadd ejabberd # sudo useradd –g ejabberd –d /opt/ejabberd-2.0.1 ejabberd
Damit der Benutzer auf die Daten in seinem Home-Verzeichnis zugreifen darf, übereignen Sie die Rechte an dem Verzeichnis und allen darin enthaltenen Verzeichnissen und Dateien dem Benutzer ejabberd: # sudo chown –R ejabberd:ejabberd /opt/ejabberd-2.0.1/
249
4.4
4
Serverdienste
Für den Start des Ejabberd gibt es das Skript ejabberd.init im Verzeichnis /opt/ ejabberd-2.0.1/bin. Leider hat das Skript einen kleinen Schönheitsfehler. Aus unerklärlichen Gründen setzt es in Zeile 3 die Bash-Option nounset. Das führt dazu, dass das Verwenden uninitialisierter Variablen zu einem Fehler und damit zu einem Abbruch des Skriptes führt. In Zeile 14 prüft das Skript die Variable $1, die in der Bash den ersten Kommandozeilenparameter enthält (sofern gesetzt). Da ein Init-Skript stets mit einem Kommando (start, stop, restart etc.) aufgerufen wird, ist diese Prüfung durchaus angebracht. Allerdings sollte ein Init-Skript, wenn es ohne Parameter aufgerufen wird, eine Liste der möglichen Optionen ausgeben. Dies ist in dem vorliegenden Skript auch vorgesehen, und zwar in den Zeilen 35–37. Allerdings wird das Skript diese Zeilen nie ausführen, da der Aufruf ohne Kommandozeilenparameter immer zu einem Fehler führen wird – dank der Option nounset. Um ein standardkonformes Verhalten des Skriptes zu erhalten, kommentieren Sie daher einfach die Zeile 3 aus: # set –o nounset
Anschließend erzeugen Sie einen symbolischen Link nach /etc/init.d … # sudo ln -s /opt/ejabberd-2.0.1/bin/ejabberd.init /etc/init.d/
… und lassen den Ejabberd beim Systemstart automatisch hochfahren: # sudo rc-update add ejabberd.init default * ejabberd.init added to runlevel default
4.4.3
Benutzerverwaltung und Client-Konfiguration
Zum Chatten fehlt jetzt nur noch ein Client. Ein guter Client ist der Open-SourceClient PSI14, den es für Linux, OS X und Windows gibt. Eine Liste verfügbarer Jabber-Clients finden Sie auch auf der Website der XFS unter http://www.jabber.org/ clients. Die folgende Beschreibung bezieht sich auf die Verwendung von PSI. Als eigenen Account werden Sie vermutlich den während der Installation eingerichteten Administrator-Account verwenden. Bei der Einrichtung des JabberClients ist es wichtig, den Benutzernamen – die Jabber-ID – in der kompletten Form anzugeben, also bestehend aus dem eigentlichen Benutzernamen und dem Systemnamen (Abbildung 4.52).
14 http://psi-im.org/
250
Jabber
Abbildung 4.52
Konfiguration der Jabber-ID in PSI
Der Jabber-Client ermittelt den Namen des Jabber-Servers eigentlich aus dem Systemnamen in der Jabber-ID. Falls der Systemname kein gültiger DNS-Name ist, müssen Sie dies in der Konfiguration des Kontos im Client entsprechend anpassen. Bei PSI können Sie das im Account-Setup auf dem Reiter Connection. Dort geben Sie auch an, dass sich PSI über SSL auf Port 5223 verbinden und dabei Legacy SSL verwenden soll (Abbildung 4.53).
Abbildung 4.53
Server- und SSL-Konfiguration in PSI
251
4.4
4
Serverdienste
Wenn Sie sich zum ersten Mal mit Ihrem frisch installierten Jabber-Server verbinden, wird Ihnen PSI anzeigen, dass das SSL-Zertifikat nicht gültig ist (SSL-Fehlermeldung von PSI). Falls Sie kein offizielles SSL-Zertifikat verwenden und Ihnen die Fehlermeldung lästig ist, können Sie PSI über die Option Ignore SSL warnings anweisen, keine Fehlermeldungen mehr im Zusammenhang mit SSL anzuzeigen (Abbildung 4.53).
Abbildung 4.54
SSL-Fehlermeldung von PSI
Neue Benutzer können sich über ihren Jabber-Client ein eigenes Konto anlegen. In der Standardkonfiguration erlaubt Ejabberd dies. Damit entfällt das umständliche Einrichten neuer Benutzer durch den Administrator. Zum Registrieren eines neuen Benutzers muss dieser beim Einrichten des Benutzerkontos in PSI die Option Register new account aktivieren (Abbildung 4.55).
Abbildung 4.55
Anlegen eines neuen Benutzerkontos
In den Details des neuen Benutzeraccounts ist – sofern notwendig – der Server wieder separat anzugeben (Abbildung 4.56). Beim Einsatz von SSL muss der zu verwendende TCP-Port auf 5223 stehen. Durch Abwählen der Option Probe legacy SSL port lässt sich der Registriervorgang beschleunigen, denn damit verhindert man, dass PSI selbständig nach einem offenen SSL-Port auf dem Server sucht. Zum Abschluss der Registrierung fragt PSI noch den Benutzernamen und das gewünschte Passwort ab – damit ist das Anlegen und Registrieren des Benutzers komplett (Abbildung 4.57).
252
Jabber
Abbildung 4.56
Details des neuen Jabber-Benutzers
Abbildung 4.57
Benutzername und Passwort des neuen Benutzers
Jabber unterstützt neben 1:1-Unterhaltungen auch Gruppenchats, so genannte Multi-User-Chats (MUC). Dazu enthält Ejabberd das Modul mod_muc. Standardmäßig ist das Modul so konfiguriert, dass nur der Administrator Chaträume anlegen darf. Wenn Sie Ihren Benutzern aber mehr Freiheiten gönnen möchten, erlauben Sie ihnen das Anlegen von Chaträumen in Eigenregie. Dazu müssen Sie in der Konfigurationsdatei des Ejabberd ejabberd.cfg die Konfiguration des Moduls mod_muc suchen und wie folgt anpassen:
Nach der Änderung muss Ejabberd neu gestartet werden. Anschließend können über den Hostnamen conference.<servername> beliebige Gruppenchats eingerichtet werden (Abbildung 4.58).
Abbildung 4.58
Einrichten eines Chatrooms
Abbildung 4.59
Aktiver Gruppenchat
Nicht jeder Benutzer ist auf dem Server erwünscht, einige Benutzer vergessen von Zeit zu Zeit ihr Passwort oder nehmen den Dienst nicht mehr in Anspruch und möchten ihr Konto gelöscht bekommen etc. Daher muss der Jabber-Admi-
254
Jabber
nistrator die Möglichkeit haben, Benutzer zu verwalten. Eine Möglichkeit hierzu stellt die fragwürdige Administrationsoberfläche dar – die wesentlich effizientere Möglichkeit ist über das Programm ejabberdctl gegeben. Ein Benutzerkonto können Sie über den folgenden Befehl löschen: ejabberdctl unregister <server>
Der Benutzer ist dabei lediglich der eigentliche Benutzername ohne den Servernamen als Postfix. Über den Servernamen setzt ejabberdctl dann den kompletten Benutzernamen zusammen. Da Sie auf einem Ejabberd-Server mehrere virtuelle Jabber-Server betreiben können, ist die Angabe des Servers notwendig. Um den Benutzer foo auf dem Server jabber.rodewig.de zu löschen ist also der folgende Befehl notwendig: # sudo ejabberdctl unregister foo jabber.rodewig.de
Benutzer löschen mit Tücken Wenn Sie das Konto eines ungebetenen Benutzers löschen, dabei aber das Registrieren neuer Benutzer über Jabber-Clients erlaubt haben, steht es diesem Benutzer natürlich frei, sich ein neues Konto anzulegen. Daher sollten Sie stets abwägen, ob ein restriktiv administrierter Server, bei dem sich Benutzer nicht selbst Konten anlegen können, notwendig ist. Auf Servern, auf denen es häufig zu Belästigungen durch undisziplinierte Benutzer kommt, kann so etwas durchaus sinnvoll sein. Neue Benutzer können Sie dann auch über ejabberdctl anlegen: # sudo ejabberdctl register <server> <passwort>
Ab einer bestimmten Anzahl von Benutzern auf Ihrem Jabber-Server werden Sie – und das ist so sicher wie das Amen in der Kirche – Anfragen von Benutzern bekommen, die ihr Passwort vergessen haben. Der einfache Weg ist das Löschen und Neuanlegen des betreffenden Benutzerkontos. Es gibt allerdings noch einen eleganteren Weg. Ejabberd speichert die Benutzerpasswörter im Klartext (pfui!). Das ist wirklich nicht zeitgemäß, denn das Prüfen von Zugangsberechtigungen über Hash-Werte ist schon lange Standard. Wie dem auch sei, über das Programm ejabberdctl kann man einen Dump der Benutzerdatenbank erzeugen. Der Befehl dazu ist dump. Über den Befehl backup kann man zwar auch ein Backup der Benutzerdatenbank anlegen, allerdings ist die Dump-Datei dann in einem für den Administrator nicht verständlichen Binärformat und dient nur zur Datensicherung. Um auf die Benutzerdatenbank zugreifen zu können, müssen Sie als Benutzer ejabberd angemeldet sein bzw. als der Benutzer, mit dessen Rechten der Ejabberd läuft. Machen Sie sich im ersten Schritt also zum Ejabberd-Benutzer:
255
4.4
4
Serverdienste
# sudo su - ejabberd sudo: ejabberd@hardy:~$
Anschließend können Sie über ejabberdctl den Dump der Benutzerdatenbank erzeugen und in der dabei angelegten Datei nach dem String »passwd« suchen: ejabberd@hardy:~$ /usr/sbin/ejabberdctl dump dump.txt ejabberd@hardy:~$ cat dump.txt |grep pass {passwd,[{record_name,passwd},{attributes,[us,password]}]}, {passwd,{"foo","jabber.rodewig.de"},"1234qwer"}. {passwd,{"kr","jabber.rodewig.de"},"1234qwer"}.
Sie sehen: Nicht nur die Passwörter der Benutzer stehen im Klartext im Datenbank-Dump, sondern auch das des Administrators. Passwortverwaltung wie zu Opas Zeiten Nicht nur der Datenbank-Dump enthält das Passwort im Klartext, sondern auch die Datei, in welcher der Ejabberd die Passwörter speichert! Unter Ubuntu ist das die Datei /var/lib/ejabberd/passwd.DCD. Unter Gentoo bei der Verwendung des Installers von der Ejabberd-Website und unter Annahme der Standardeinstellungen liegt die Datei im Verzeichnis /opt/ejabberd-2.0.1/database/ejabberd@localhost. Da diese Datei eine Binärdatei ist, können Sie mit einem cat oder less zwar nicht viel Brauchbares erkennen, zumindest aber die Benutzerpasswörter im Klartext. Deutlicher wird es bei der Betrachtung mit einem Hexeditor: # hexdump -C passwd.DCD | awk ' {print $18}' |....cXM....JbWLA| |.h.d..log_header| |d..dcd_logk..1.0| |k..4.3.5d..ejabb| |[email protected]....| |b....b..xS...3bW| |LA.h.d..passwdh.| |k..fook..jabber.| |rodewig.dek..123| |4qwer...2bWLA.h.| |d..passwdh.k..kr| |k..jabber.rodewi|
Wirklich dramatisch daran ist, dass die Dateiberechtigungen bei der Verwendung des Installers so stehen, dass jeder Benutzer des Systems diese Dateien lesen darf! Unter Ubuntu sind die Dateirechte zwar genauso katastrophal gesetzt, immerhin ist aber das Wurzelverzeichnis des ejabberd-Benutzers auf 700 gesetzt, so dass nur der Besitzer selbst die darin enthaltenen Dateien lesen kann. Eine Systemhärtung im Sinne eines Defense-in-Depth-Ansatzes stellt das auch nicht dar. Sie sollten daher die Dateiberechtigungen unbedingt so stellen, dass nur der ejabberd-Benutzer auf diese Dateien und Verzeichnisse zugreifen darf.
256
Jabber
Setzen Sie zunächst die Rechte des Ejabberd-Wurzelverzeichnisses selbst auf 700: # sudo chmod 700 /var/lib/ejabberd
bzw. # sudo chmod 700 /opt/ejabberd-2.0.1
Anschließend setzen Sie die Rechte aller Verzeichnisse darunter auf 700 und die Rechte aller Dateien auf 600: # find /var/lib/ejabberd/ -type d –exec chmod 700 {} \; # find /var/lib/ejabberd/ -type f –exec chmod 600 {} \;
bzw. # find /opt/ejabberd-2.0.1/ -type d –exec chmod 700 {} \; # find /opt/ejabberd-2.0.1/ -type f –exec chmod 600 {} \;
4.4.4
Ejabberd mit eigenem SSL-Zertifikat
Wenn Sie Ejabberd mit einem eigenen SSL-Zertifikat betreiben möchten, haben Sie wie beim Apache-Server die Möglichkeit, einfach ein eigenes Zertifikat mit OpenSSL zu erstellen und dieses von Ejabberd verwenden zu lassen. Das bei Ejabberd mitgelieferte Zertifikat enthält zwar den Hostnamen des Systems, auf dem der Server installiert ist, ansonsten aber keine Ihrer Daten: # openssl x509 -text -inform pem -in /etc/ejabberd/ejabberd.pem Certificate: Data: Version: 3 (0x2) Serial Number: e4:e4:13:66:6b:5e:81:ab Signature Algorithm: sha1WithRSAEncryption Issuer: O=Internet Widgits Pty Ltd, OU=hardy, CN=ejabberd/ emailAddress=root@hardy. Validity Not Before: Jul 25 16:07:53 2008 GMT Not After : Jul 25 16:07:53 2009 GMT Subject: O=Internet Widgits Pty Ltd, OU=hardy, CN=ejabberd/ emailAddress=root@hardy. Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public Key: (1024 bit) Modulus (1024 bit): [...]
Wie beim Apache können Sie mit OpenSSL ein eigenes Zertifikat erstellen: # openssl req -new -x509 -days 365 -nodes -out server.crt -keyout server.key Generating a 1024 bit RSA private key
257
4.4
4
Serverdienste
..++++++ ........++++++ writing new private key to 'server.key' ----You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----Country Name (2 letter code) [AU]:DE State or Province Name (full name) [Some-State]:NRW Locality Name (eg, city) []:Cologne Organization Name (eg, company) [Internet Widgits Pty Ltd]:Foo Ltd. Organizational Unit Name (eg, section) []:IT Common Name (eg, YOUR name) []:jabber.rodewig.de Email Address []:[email protected]
Achten Sie darauf, dass der Name des Servers im Feld Common name codiert sein muss. Den Fingerprint des erzeugten Zertifikates können Sie ebenfalls über OpenSSL anzeigen lassen: # openssl x509 -subject -dates -fingerprint -noout -in server.crt subject= /C=DE/ST=NRW/L=Cologne/O=Foo Ltd./OU=IT /CN=jabber.rodewig.de/[email protected] notBefore=Jul 29 17:46:54 2008 GMT notAfter=Jul 29 17:46:54 2009 GMT SHA1 Fingerprint= B3:45:75:D3:F7:E5:D5:9F:5C:C9:9F:7B:5D:81:85:B7:FB:45:F2:34
Aufgrund der Eigenheit des Ejabberd müssen Sie Zertifikat und privaten Schlüssel in eine einzige Datei kopieren. Einen Dialog zum Abfragen eines Passwortes für den privaten Schlüssel kennt Ejabberd auch nicht – Sie dürfen für den privaten Schlüssel daher kein Passwort vergeben. Sicherheit scheint bei den Entwicklern des Ejabberd anscheinend nicht großgeschrieben zu werden. # cat server.key server.crt > server.pem
258
Jabber
Jetzt müssen Sie nur noch in der Konfigurationsdatei ejabberd.cfg das neue Zertifikat eintragen. Dazu suchen Sie den SSL-Listener und passen die Direktive certfile entsprechend an: % SSL-enabled client-2-server service [ {5223, ejabberd_c2s, [{access, c2s}, {max_stanza_size, 65536}, tls, {certfile, "/etc/ejabberd/server.pem"}, {shaper, c2s_shaper}]}
Nach einem Neustart des Servers wird das neue Zertifikat verwendet. PSI wird Ihnen – da es kein offizielles Zertifikat ist – eine Fehlermeldung anzeigen. Diese können Sie nutzen, um die Daten des Zertifikates zu überprüfen (Abbildung 4.60).
Abbildung 4.60 Zertifikatsdetails in PSI
4.4.5
Ein eigenes – offizielles – SSL-Zertifikat
Beim produktiven Einsatz im Internet sind selbsterstellte und selbstsignierte Zertifikate nur eingeschränkt sinnvoll. Ältere Browser geben störende Hinweise aus, wenn ein Zertifikat nicht von einer offiziellen CA ausgestellt ist. Aktuelle Browser wie der Internet Explorer in der Version 7 und Firefox in der Version 3 erfordern sogar einige Handgriffe, um eine SSL-verschlüsselte Website trotz eines nicht offiziellen Zertifikates ansehen zu können. Für den professionellen Einsatz besteht die Möglichkeit, ein Zertifikat zu kaufen, für den hobbymäßigen Einsatz ist diese
259
4.4
4
Serverdienste
Möglichkeit aber häufig zu kostspielig. Glücklicherweise gibt es einige Anbieter, die kostenlose Zertifikate für den nichtkommerziellen Gebrauch anbieten. Die bekanntesten Anbieter sind CAcert15 und Thawte.16 CAcert bietet die Möglichkeit, X.509-Zertifikate für SSL-Verschlüsselung und S/MIME zu erhalten. Die SSL-Zertifikate können Sie im Apache oder in Ejabberd verwenden. S/MIME-Zertifikate können Sie in Ihrem E-Mail-Client einsetzen, um verschlüsselte und signierte E-Mails schreiben zu können. Der Vorteil von CAcert gegenüber kommerziellen Institutionen ist, dass die Mitgliedschaft und das Ausstellen von Zertifikaten kostenlos sind. Der Nachteil ist, dass die Root-CA von CAcert in kaum einem Programm, egal ob Browser oder E-Mail-Programm, als vertrauenswürdige CA enthalten ist. Daher müssen Benutzer, die Zertifikaten von CAcert vertrauen sollen, zunächst das Root-Zertifikat von CAcert in ihr Programm importieren. Auf der Website gibt es einen Link zu verschiedenen Versionen des Root-Zertifikates. Um das Root-Zertifikat in Firefox zu importieren, rufen Sie im Firefox die URL http://www.cacert.org/certs/class3.crt auf, wählen im sich öffnenden Dialog alle Optionen aus und bestätigen die Auswahl mit dem OK-Button (Abbildung 4.61). CAcert arbeitet mit einem Web of Trust, in dem sich die CAcert-Mitglieder gegenseitig beglaubigen können. Durch Beglaubigungen kann man Punkte sammeln, die ein Maß für die Vertrauenswürdigkeit innerhalb des Web of Trust sind. Über Formulare, die auf der Website von CAcert erhältlich sind, kann man sich bei glaubwürdigen Personen wie Rechtsanwälten, Notaren etc. gegen Vorlage eines amtlichen Dokumentes identifizieren lassen. Dieses Vorgehen ist analog zur Überprüfung einer Identität für PGP- oder GPG-Verschlüsselung durch eine glaubwürdige Institution.
Abbildung 4.61 Importieren des CAcert-Root-Zertifikates in Firefox 15 www.cacert.org 16 www.thawte.com/
260
Jabber
Um ein Zertifikat von CAcert zu erhalten, müssen Sie sich dort zunächst anmelden. Anmeldung und Mitgliedschaft sind kostenlos. Anschließend konfigurieren Sie in Ihrem Profil eine Domain, für die Sie ein Zertifikat erzeugen möchten. Alle Operationen zum Anlegen von Domains oder E-Mail-Adressen werden mit Kontroll-E-Mails überprüft. Sie erhalten nach einer Transaktion eine E-Mail mit einem Link, über den Sie die Gültigkeit der Transaktion bestätigen müssen. Auf diese Weise wird sichergestellt, dass Sie keine Zertifikate für E-Mail-Adressen oder Domains ausstellen, für die Sie nicht autorisiert sind. Nachdem das persönliche Profil eingerichtet ist, muss ein Certificate Signing Request (CSR) erstellt werden. Dieser enthält alle Daten des Zertifikates, aus denen CAcert dann das signierte Zertifikat erzeugt. Einen CSR erzeugen Sie mit OpenSSL über den folgenden Befehl: # openssl req -nodes -new -keyout server.key -out server.csr Generating a 1024 bit RSA private key .....................................++++++ ...........++++++ writing new private key to 'server.key' ----You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----Country Name (2 letter code) [AU]:DE State or Province Name (full name) [Some-State]:NRW Locality Name (eg, city) []:Cologne Organization Name (eg, company) [Internet Widgits Pty Ltd]:Foo Ltd. Organizational Unit Name (eg, section) []:IT Common Name (eg, YOUR name) []:jabber.rodewig.de Email Address []:[email protected] Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []: An optional company name []:
Auch hier gilt: Der Common Name muss der Name des Servers sein, auf dem das Zertifikat verwendet werden soll. Im vorstehenden Fall ist das Zertifikat für einen Jabber-Server gedacht, bei einem Webserver wäre der Common Name dann beispielsweise entsprechend www.rodewig.de o. Ä.
261
4.4
4
Serverdienste
In der erzeugten Datei server.csr befindet sich anschließend der CSR, in der Datei server.key der private Schlüssel zum Zertifikat: # cat server.csr -----BEGIN CERTIFICATE REQUEST----MIIBzzCCATgCAQAwgY4xCzAJBgNVBAYTAkRFMQwwCgYDVQQIEwNOUlcxEDAOBgNV [...] hbHuqfGg7aCBfnVzXbE3AeGTYe8N7cwE8AQZNgSvQrf5EvA= -----END CERTIFICATE REQUEST----# cat cacert.key -----BEGIN RSA PRIVATE KEY----MIICWwIBAAKBgQDCrg2wziFUWjkezYOU9PSQW/44arjAM44bS2/qAg62zZjSp1Ds [...] TKoW2b2nCx14GcVcaJGTFyHQgP9xpcgqL2WCEklJFQ== -----END RSA PRIVATE KEY-----
Den CRS kopieren Sie in das entsprechende Online-Formular auf der CAcertWebsite und erhalten im Gegenzug das signierte Zertifikat: # cat cacert.crt -----BEGIN CERTIFICATE----MIIEVzCCAj+gAwIBAgIDBYxQMA0GCSqGSIb3DQEBBQUAMHkxEDAOBgNVBAoTB1Jv [...] H1lrBHaMAwu+msM= -----END CERTIFICATE-----
Den Inhalt des Zertifikates können Sie mit OpenSSL prüfen: # openssl x509 -text -inform pem -in cacert.crt Certificate: Data: Version: 3 (0x2) Serial Number: 363600 (0x58c50) Signature Algorithm: sha1WithRSAEncryption Issuer: O=Root CA, OU=http:// www.cacert.org, CN=CA Cert Signing Authority/ [email protected] Validity Not Before: Jul 29 18:19:07 2008 GMT Not After : Jan 25 18:19:07 2009 GMT Subject: CN=jabber.rodewig.de Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public Key: (1024 bit) [...]
Wenn Sie das Zertifikat im Apache-Webserver verwenden wollen, gehen Sie vor wie in Abschnitt 4.1.4 beschrieben. Kopieren Sie Zertifikat und Schlüssel in ein
262
Mailversand
geeignetes Verzeichnis, und konfigurieren Sie den SSL-Host des Apache so, dass er beide Dateien verwendet. Um das Zertifikat mit Ejabberd zu verwenden, müssen Sie den Schlüssel und das Zertifikat – wie in Abschnitt 4.4.4 beschrieben – in eine Datei kopieren und diese Datei in der Datei ejabberd.cfg als Zertifikatsdatei angeben.
4.5
Mailversand
Eine gängige Anforderung an einen Webserver ist die Fähigkeit, E-Mails versenden zu können. Webapplikationen verwenden Mailversand für verschiedenste Zwecke: Versand von Newslettern, Grußkarten, Anmeldebestätigungen, Registrierungsinformationen … die Liste der Dienste kann beliebig erweitert werden. Leider ist es häufig so, dass Programmierer und Administratoren den Mailversand von Webapplikationen über einen lokal installierten Mailserver abwickeln. Das ist zwar eine naheliegende Lösung, zumal Administratoren gerne alles auf ihren Systemen unter ihrer Kontrolle haben möchten, aber schon deswegen keine gute Idee, weil es nur sehr wenige Administratoren gibt, die einen umfassenden Überblick über die Möglichkeiten haben, die ein moderner Mailserver bietet. Allein das Referenzhandbuch zum weitverbreiteten Sendmail-Server umfasst 1300 Seiten! E-Mail gehört wahrscheinlich zu den am meisten unterschätzten Diensten im Internet – allerdings auch zu den unter Spitzbuben am beliebtesten Diensten, denn mit kaum einer Dienstleistung wird im dunklen Teil des Internets mehr Geld verdient als mit Spam. Ein ungesicherter oder falsch konfigurierter Mailserver ist daher eine Goldgrube für einen Spam-Versender. Beim Einsatz eines Mailservers für den Mailversand von einer Webapplikation aus gibt es drei potentielle Angriffsmöglichkeiten. Die eine ist der Dienst selbst, der – wie jede andere Software auch – Sicherheitslücken aufweisen kann. Eine andere ist eine fehlerhaft programmierte Webapplikation, die Benutzereingaben ungefiltert an den lokalen Mailserver weitergibt und darüber von einem Angreifer für Spamzwecke missbraucht werden kann. Die dritte Angriffsmöglichkeit besteht darin, dass ein Angreifer den Server kompromittieren und über den lokalen Mailserver Spam-Mails absetzen kann. Alle drei Angriffsmöglickeiten lassen sich relativ leicht beseitigen: Installieren Sie einfach keinen Mailserver. Ein ungesicherter Mailserver ist auf TCP-Port 25 erreichbar, nimmt E-Mails entgegen und sendet sie weiter. Ist der Server nicht ausreichend konfiguriert, kann ein Angreifer über diesen Weg E-Mails an beliebige Empfänger versenden, das perfekte Spam-Relay. Wenn Sie den Mailserver über eine Host-Firewall so schützen, dass von außen keine Verbindung auf Port 25 erlaubt ist, ist zwar die konkrete Bedro-
263
4.5
4
Serverdienste
hung beseitigt, das grundsätzliche Problem besteht aber weiter – die Konfiguration des Servers. Sich in die Konfiguration eines Mailservers einzuarbeiten, um von einer Webapplikation aus Mails zu versenden, ist ziemlicher Overkill. Zwar ist nicht jeder Mailserver so mächtig und undurchsichtig wie Sendmail, aber auch einfacher zu konfigurierende Mailserver wie z. B. Qmail haben es in sich. In der Vergangenheit sind schlecht programmierte Mailformulare in Webapplikationen häufig für Spam-Versand ausgenutzt worden. Eine klassische Lücke sind Skripte, die Benutzereingaben ungefiltert an Sendmail übergeben. Ein SendmailAufruf in einem CGI-Skript würde dann z. B. wie folgt aussehen: [...] open(SEND,"|/usr/sbin/sendmail -t -f -odq webapp\ @rodewig.de") print SEND <<EOF; To: webapp\@rodewig.de Subject: Gewinnspiel From: $sender [...]
Das Skript scheint unbestechlich. Die Empfängeradresse ist festgelegt, scheinbar kann das Skript also nicht für Spam-Zwecke missbraucht werden. Allerdings ist Sendmail tückisch. Believe it or not: Im From-Feld der E-Mail können mit dem Schlüsselwort To: weitere Empfänger angegeben werden! Für einen Angreifer ist es damit ein Leichtes, über das Einfügen von Sonderzeichen das From-Feld so zu manipulieren, dass das Skript E-Mails an beliebige Empfänger versenden kann – fertig ist die perfekte Spam-Schleuder. Die Ursache ist eine Kombination aus schlechter Programmierung – das fehlende Filtern von Sonderzeichen – und den kreativen Einsatzmöglichkeiten von Sendmail. Wenn Sie über Ihren Webserver E-Mails versenden möchten, nutzen Sie ausschließlich die Möglichkeiten der eingesetzten Programmiersprache. Alle gängigen Programmiersprachen für Webapplikationen, sei es PHP, Perl, Python, Java o. Ä., bieten die Möglichkeit, E-Mails direkt aus der Applikation heraus zu versenden, und das meist wesentlich komfortabler als über einen lokalen Mailserver. Eine umfassende Protokollierung zu erstellen ist ebenfalls kein Problem für einen geübten Programmierer, so dass das Standardargument von Administratoren, dass über selbsterstellte Mailformulare versandte Mails nicht im Systemlog auftauchen, schnell entkräftet werden kann. Achten Sie darauf, dass ein Mailskript alle Benutzereingaben auf Sonderzeichen filtert, und prüfen Sie die Funktionalität aller Mailskripte auf Missbrauchsmöglichkeiten. Im Gegensatz zu einem komplexen Dienst wie einem Mailserver ist dies eine realistische Aufgabe. Lassen Sie sich nicht auf den Tanz mit dem Teufel (Mailserver) ein, als Unkundiger holt man sich dabei nur blaue Flecken und blutige Füße.
264
Dateitransfer
4.6
Dateitransfer
Steht ein Server im Internet, müssen irgendwie Daten auf das System gelangen. Ein Webserver dient zwar in der Regel dazu, Daten an Benutzer auszuliefern, allerdings müssen die auszuliefernden Daten erst einmal auf das System kommen. Für diesen Zweck gibt es Protokolle für den Dateitransfer. Der wohl älteste und leider immer noch verbreitetste Vertreter ist das File Transfer Protocol (FTP). FTP ist ein wahrer Dinosaurier unter den Protokollen. Es ist umständlich, da Steuerund Datenkanäle getrennt sind und bei der sicheren Konfiguration von Firewalls regelmäßig Probleme bereiten. Obendrein ist FTP ein Klartextprotokoll, d. h., alle Daten – inklusive der Login-Daten – gehen im Klartext durch die Leitung. Mit einem Netzwerksniffer wie tcpdump oder Wireshark kann ein Angreifer so ohne großen Aufwand in den Besitz sensibler Daten gelangen. Abbildung 4.62 zeigt den Wireshark-Mitschnitt vom Aufbau einer FTP-Verbindung. Der Benutzername (»klaus«) und das dazugehörige Passwort (»klaus«) sind ohne Probleme zu erkennen.
Abbildung 4.62 FTP-Zugangsdaten im Netzwerksniffer
In Zeiten von Modemverbindungen ins Internet bestand zwar auch schon die Gefahr, dass ein Angreifer den Netzwerkverkehr mitschneidet, allerdings ist die Gefahr heutzutage eher größer als geringer geworden. Viele Leute gehen an ihnen unbekannten Hotspots per WLAN ins Internet und übertragen sensible Daten über Klartextprotokolle. Dabei vergessen viele, dass in der Regel alle, die am selben Hotspot angemeldet sind, den gesamten Netzwerkverkehr aller Teilnehmer mitlesen können. Das Verwenden von Klartextprotokollen in solchen Netzwerken mit unbekannten Teilnehmern kann daher schon als grob fahrlässig bezeichnet werden. Glücklicherweise gibt es wesentlich sicherere Alternativen, so dass FTP heutzutage gar nicht mehr benutzt werden muss. Mit FTPS steht eine Alternative zu FTP zur Verfügung, bei der die Daten über SSL gesichert werden. SCP und SFTP haben mit FTP gar nichts gemeinsam und bauen auf SSH auf. Alle drei Protokolle eignen sich für einen sicheren und effizienten Datenaustausch mit Ihrem Server.
265
4.6
4
Serverdienste
4.6.1
FTPS
Ein bewährter, performanter und stabiler FTP-Daemon ist der ProFTPD. ProFTPD ist ein unter der GPL veröffentlichter Open-Source-Server mit einer mittlerweile langen Tradition. Diese Tradition ist nicht ungetrübt, denn leider hat der ProFTPD in der Vergangenheit immer wieder durch schwere Sicherheitslücken von sich reden gemacht. Viele dieser Sicherheitslücken waren Buffer Overflows, durch die ein Angreifer Code auf dem Serversystem mit den Rechten des ProFTPD-Benutzers ausführen konnte. Buffer Overflows sind Sicherheitslücken, die in Programmiersprachen auftreten können, die keine automatische Längenüberprüfung bei Operationen durchführen. ProFTPD ist in C geschrieben, und C ist das Paradebeispiel einer solchen Sprache, denn alle Sicherheitsmerkmale moderner Programmiersprachen wie Bound Checking oder Speichermanagement sucht man in C vergeblich. Glücklicherweise ist das Entwicklerteam des ProFTPD recht aktiv, so dass ein auf einem aktuellen Stand befindliches System eine angemessene Sicherheit bieten sollte. Ein Vorteil des ProFTPD ist seine Modularität. Ähnlich wie den Apache-Webserver kann man auch bei ProFTPD mit Modulen die Funktionalität erweitern, und überdies beherrscht der Server – ebenfalls wie der Apache – das Betreiben virtueller Hosts. Module können fest in den Server einkompiliert oder dynamisch nachgeladen werden. Das für den Betrieb von FTPS notwendige Modul mod_tls ist beim Gentoo-Paket bereits einkompiliert, unter Ubuntu wird es dynamisch geladen und kann nach der Installation umgehend verwendet werden. Die Installation ist gewohnt einfach. Unter Ubuntu: # sudo apt-get install proftpd
Unter Gentoo: # sudo emerge proftpd
Interessanterweise ist die Version unter Ubuntu 1.3.1, unter Gentoo zum Zeitpunkt der Manuskripterstellung nur der Release-Candidate 2 dieser Version. Ubuntu: # proftpd -v - ProFTPD Version 1.3.1
Gentoo: # proftpd -v - ProFTPD Version 1.3.1rc2
266
Dateitransfer
ProFTPD unter Gentoo Interessant ist die unter Gentoo verfügbare ProFTPD-Version, weil RC2 von Januar 2007 ist, im Juli 2007 noch RC3 herausgekommen ist und im Oktober 2007 die finale Version 1.3.1 veröffentlicht wurde. Angesichts der Sicherheitslücken, die in ProFTPD immer wieder entdeckt werden, ist es sehr bedenklich, so alte Versionen in einer Distribution zu verwenden. In der finalen Version 1.3.1 wurde zumindest eine Schwachstelle beseitigt, die ein Angreifer für einen Denial-of-Service-Angriff verwenden könnte.
Neben der Modularität war der ProFTPD einer der ersten FTP-Server, bei dem Benutzerzugriffe auf bestimmte Verzeichnisse beschränkt werden konnten, so genannte Jailings. Bei älteren FTP-Servern, wie z. B. dem betagten Wu-FTPD, konnten Benutzer grundsätzlich auf das gesamte Dateisystem zugreifen – soweit es ihre Rechte zuließen. Aus der Sicht eines Administrators ein absoluter Graus, denn auch wenn dies durch ausreichend restriktiv gesetzte Dateiberechtigungen kein direktes Sicherheitsrisiko darstellt, ist es zumindest ein schwerwiegendes Informationsloch. Einen normalen Benutzer haben die Dateien und Verzeichnisse des Betriebssystems und die anderer Benutzer einfach nicht zu interessieren. Da FTPS über SSL läuft, kann der ProFTPD auch mit einem eigenen Zertifikat ausgestattet werden. Wenn es etwas Offizielles sein darf, kann auch hier ein Zertifikat von CAcert (oder anderen CAs) zum Einsatz kommen. Wie Sie ein eigenes Zertifikat erstellen, ist in Abschnitt 4.4.5 beschrieben. Das Einbinden in den ProFTPD geschieht über die Konfiguration des Moduls mod_tls. Eine einfache Konfigurationsdatei für den ProFTPD, mit dem Benutzer auf ihre Home-Verzeichnisse zugreifen können und in diesen »festgenagelt« sind, ist die folgende, die sich an der Standardkonfiguration von Ubuntu orientiert. Die erste Direktive bindet die angegebene Datei ein, in der die vom ProFTPD zu ladenden Module aufgeführt sind. Das Aufteilen der Konfiguration auf verschiedene Dateien dient lediglich der Übersichtlichkeit, ist also keine Voraussetzung für den Betrieb des Servers. Include /etc/proftpd/modules.conf
Die zweite Direktive deaktiviert die Unterstützung für IPv6. Falls Ihr Server nicht an ein IPv6-Netzwerk angeschlossen ist, können Sie IPv6 im Sinne einer Serverhärtung getrost deaktivieren. Je weniger Funktionen aktiv sind, desto besser. UseIPv6
off
Mit der nächsten Direktive legen Sie fest, wie sich der Server gegenüber einem sich mit einem FTP-Client verbindenden Benutzer melden soll. Der Name, den Sie hier angeben, wird dem Client nach dem Connect, aber vor dem Abfragen der Zugangsdaten angezeigt.
267
4.6
4
Serverdienste
ServerName
"Hardy FTP-Server Foomatic Ltd."
Das Ergebnis kann mit einem Kommandozeilen-Client überprüft werden: # ftp localhost Connected to localhost. 220 ProFTPD 1.3.1 Server (Hardy FTPServer Foomatic Ltd.) [127.0.0.1] [...]
In den Anfangszeiten von Linux war der Inetd-Daemon sehr beliebt und bei den damals »großen« Distributionen wie SuSE oder Red Hat standardmäßig immer aktiviert. Der Inetd ist ein Wrapper-Daemon, der bereits in frühen BSD-Versionen eingeführt wurde und der auf konfigurierten Ports nach eingehenden Verbindungen lauscht und bei Bedarf für Ports, auf denen Verbindungen eingehen, die entsprechenden Serverdienste startet. Wird ein Dienst nicht mehr benötigt, stoppt der Inetd diesen Dienst wieder. Die Philosophie dahinter ist, dass ein Netzwerkdienst nur so lange aktiv ist, wie er benötigt wird, und dass die eigentliche Netzwerkkommunikation nicht von den Serverdiensten selbst, sondern vom Inetd durchgeführt wird. Dieser kommuniziert mit den von ihm gestarteten Diensten nicht über ein Netzwerkprotokoll, sondern über die Handler stdin und stdout. Damit entfällt für die vom Inetd verwalteten Dienste die Notwendigkeit, die jeweiligen Netzwerkprotokolle selbst implementieren zu müssen – die einzige Netzwerkschnittstelle zu den Clients ist der Inetd. Während es für den Apache-Webserver aus Performancegründen nicht sinnvoll ist, über den Inetd verwaltet zu werden, da der Server für jede neue Verbindung gestartet werden muss, kann bei einem nicht übermäßig beanspruchten FTP-Server der Einsatz des Inetd mitunter sinnvoll sein. Allerdings bleibt dabei zu beachten, dass sich die Systemsicherheit nicht dadurch erhöhen lässt, dass man die Netzwerkkommunikation von einem Dienst auf einen anderen transferiert. Der Inetd hat – genauso wie jede andere Software – Fehler und Sicherheitslücken und kann daher ebenso Ziel von Angriffen werden wie andere Serverdienste (was er in der Vergangenheit auch bereits wiederholt geworden ist). Die Wahrscheinlichkeit, durch den Einsatz des Inetd einen Sicherheitsgewinn zu erzielen, steigt mit der Anzahl der Serverdienste, die vom Inetd verwaltet werden. Haben Sie nur einen Dienst, den der Inetd verwalten soll, verschieben Sie das Risiko einer Sicherheitslücke lediglich von einem Dienst zum nächsten. Verwaltet der Inetd hingegen viele Dienste, schirmt er auf diese Weise entsprechend viele Implementierungen von Netzwerkprotokollen mit potentiellen Sicherheitslücken gegen Angreifer ab. Der ProFTPD kann im Inetd-Modus laufen oder im Standalone-Modus. Dies können Sie über die Direktive ServerType festlegen. Der Wert standalone versetzt
268
Dateitransfer
den ProFTPD in den »normalen« Modus, in dem er selbst die Netzwerkkommunikation übernimmt. Der Wert inetd legt fest, dass der Inetd den ProFTPD steuert und dieser daher keine eigene Netzwerkfunktionalität zur Verfügung stellt. ServerType
standalone
Ein Server – egal welchen Typs – sollte so wenige Informationen wie möglich an nicht authentifizierte Benutzer ausgeben. Mit der folgenden Direktive können Sie steuern, ob der ProFTPD Informationen über sich ausgeben soll. Ist der Wert off, gibt der Server den mit der Direktive ServerIdent festgelegten String aus – so wie weiter oben gezeigt. Ist der Wert on, gibt der Server nur den String »ProFTPD« und seine Versionsnummer aus. Bei aus dem Internet erreichbaren Systemen sollte DeferWelcome grundsätzlich auf on stehen. DeferWelcome
on
Ist diese Direktive aktiviert, gibt der Server gegenüber dem Client keine Informationen über sich aus. Der ProFTPD unterstützt virtuelle Hosts. Für den Fall, dass kein virtueller Host konfiguriert ist oder eine Verbindung auf einer IP-Adresse eingeht, für die kein Host konfiguriert ist, können Sie über die folgende Direktive einen (virtuellen) Host als Standardhost festlegen. Ist für eine eingehende Verbindung kein Host verfügbar, verweigert der Server die Verbindung und gibt eine Fehlermeldung an den Client zurück. DefaultServer
on
Analog zur Direktive FollowSymlinks beim Apache-Webserver kann der ProFTPD mit der Direktive ShowSymlinks so eingerichtet werden, dass er neben regulären Dateien und Verzeichnissen auch symbolische Links anzeigt und deren Verwendung erlaubt. Da FTP-Server in der Regel nur zu Zwecken der Datenanlieferung und nicht für Hochlastbetrieb verwendet werden, stellt das Erlauben von Symlinks kein Performancerisiko dar. Da ein in sein Home-Verzeichnis verbannter FTP-User dieses über Symlinks nicht verlassen kann, stellt das Erlauben von Symlinks auch kein Sicherheitsrisiko dar. ShowSymlinks
on
Im Gegensatz zu HTTP ist FTP ein verbindungsorientiertes Protokoll. Ruft ein Benutzer über seinen Browser keine weiteren Daten mehr von einem Webserver ab, bleibt die TCP-Verbindung auf dem Server so lange bestehen, bis der Server sie automatisch schließt. Der Benutzer am Browser bemerkt das Schließen der Verbindung gar nicht. Beim FTP-Protokoll muss eine Verbindung explizit beendet werden, entweder vom Client oder vom Server. Es ist keine gute Idee, das
269
4.6
4
Serverdienste
Schließen der Verbindungen nur den Clients zu überlassen. Benutzer sind undiszipliniert, FTP-Clients und Betriebssysteme stürzen ab, und ohne dass eine Verbindung in einem solchen Fall explizit auf Anwendungsebene geschlossen worden ist, bleibt sie auf dem Server stehen, bis der Dienst beendet wird. Ist die Anzahl der erlaubten Verbindungen überschritten, nimmt der FTP-Server keine weiteren Verbindungen mehr entgegen, auch wenn kein einziger Client mehr mit ihm verbunden ist. Um dies zu vermeiden, müssen Sie dem ProFTPD unbedingt mitteilen, dass er inaktive Verbindungen, d. h. Verbindungen, über die keine Daten mehr gesendet werden, nach einer festgelegten Timeout-Zeit beenden soll. Dies können Sie mit verschiedenen Timeout-Direktiven, von denen die wichtigste die Direktive TimeoutIdle ist. Damit legen Sie die Zeit in Sekunden fest, nach der eine inaktive Verbindung beendet wird. Wählen Sie den Zeitraum nicht zu groß, denn im Allgemeinen gibt es keine Notwendigkeit dafür, dass ein FTPClient 10, 20 oder 60 Minuten mit einem Server verbunden sein muss, ohne dass Daten ausgetauscht werden. 60 Sekunden sind hier ein guter Wert. TimeoutIdle
60
Wenn Sie Ihren Benutzern beim Anmelden einen Spruch des Tages, eine Warnung, eine Anleitung oder sonstige Weisheiten mit auf den Weg geben möchten, können Sie über die Direktive DisplayLogin eine Datei festlegen, deren Inhalt der ProFTPD den Benutzern nach erfolgreicher Anmeldung ausgibt. DisplayLogin
welcome.msg
Ein FTP-Server läuft standardmäßig auf TCP-Port 21. Falls Sie einen anderen Port benutzen möchten oder müssen, können Sie dies über die Direktive Port festlegen. Port
21
In Abhängigkeit von der zu erwartenden Anzahl von FTP-Benutzern können Sie über die Direktive MaxInstances steuern, wie viele Clients der ProFTPD maximal erzeugen können darf. Wenn Sie den FTP-Server nur für sich selbst verwenden, um Daten von und zum Webserver zu transferieren, können Sie den Wert im einstelligen Bereich belassen. MaxInstances
5
Wie alle Prozesse läuft auch der ProFTPD mit den Rechten eines Systembenutzers. Beim Start besitzt der ProFTPD-Prozess zwar Root-Rechte, um sich an den privilegierten TCP-Port 21 binden zu können, doch sobald der Dienst gestartet und der Netzwerk-Listener eingerichtet ist, wechselt der Prozess in den Benutzerkontext des Benutzers und der Gruppe, die mit den Direktiven User und Group festgelegt worden sind. Legen Sie der Übersichtlichkeit halber für den ProFTPD
270
Dateitransfer
einen eigenen Benutzer an – sofern dies im Rahmen der Installation nicht bereits automatisch passiert ist. User Group
proftpd nogroup
Da Sie per FTP Dateien und Verzeichnisse aus dem FTP-Server anlegen können, bietet der ProFTPD die Möglichkeit, für Dateien und Verzeichnisse Umasks zu definieren. Analog zur globalen Umask des Systems sollte die Umask in der ProFTPD-Konfiguration aus Sicherheitsgründen so restriktiv wie möglich eingestellt sein. Wichtig ist das Festlegen der Umask insbesondere, weil Sie damit verhindern können, dass ein Benutzer Schadsoftware mit gesetztem SUID- oder GUID-Bit hochladen kann. Umask
077
077
Aus Sicherheitsgründen ist die Standardeinstellung des ProFTPD, dass ein FTPClient bereits auf dem Server vorhandene Dateien und Verzeichnisse nicht überschreiben darf. Für den normalen Betrieb ist das natürlich wenig praktikabel, daher sollten Sie dieses Verhalten mit der Direktive AllowOverwrite unterbinden. AllowOverwrite
on
Wie jeder anständige Server führt auch der ProFTPD Buch über seine Aktivitäten. In der über die Direktive TransferLog festgelegten Datei befinden sich Angaben zu den Dateioperationen, die Clients über FTP auf dem Server ausführen. Diese Datei ist eine wichtige Informationsquelle, wenn es um forensische Analysen oder Anfragen von Benutzern geht, die ihre Dateien nicht mehr finden können, aber angeblich »nichts gemacht haben«. Ein Blick in das Transferlog zeigt dann häufig, dass »nichts gemacht« offenbar mit dem Löschen von Daten verwechselt worden ist. TransferLog /var/log/proftpd/xferlog
Allgemeine Informationen über den Status des Servers und über Login- und Logout-Vorgänge von Benutzern sendet der ProFTPD an den lokalen Syslog-Daemon, was das Speichern und Verarbeiten dieser Daten sehr komfortabel macht. Alternativ können Sie über die Direktive SystemLog eine Datei festlegen, in die der ProFTPD die Daten schreibt, was das Senden der Daten an den Syslog-Daemon unterbindet. Falls Sie diese Methode wählen, denken Sie daran, die Datei automatisch zu rotieren. Die zwei folgenden Direktiven beschleunigen das Antwortverhalten des ProFTPD bei Login-Versuchen enorm:
271
4.6
4
Serverdienste
UseReverseDNS IdentLookups
off off
Mit der ersten Direktive, UseReverseDNS, verhindern Sie, dass der ProFTPD bei einem Login-Versuch ein Reverse-Lookup der IP-Adresse des Clients durchführt. Genau wie beim Apache-Webserver ist dieses Verhalten nur in seltenen Ausnahmefällen sinnvoll, z. B. wenn Benutzer oder Systeme über ihre Systemnamen identifiziert werden müssen. Im Standardfall führt ein Reverse-Lookup nur zu einer Zeitverzögerung beim Login, was sich bei stark belasteten Systemen durchaus bemerkbar machen kann. Ein Überbleibsel aus der Zeit, als das Internet noch grau und die Benutzer noch vertrauenswürdig waren, sind Ident-Lookups. Diese führt der ProFTPD bei einer eingehenden Verbindung standardmäßig durch. Über Ident-Lookups17 wurden vor langer Zeit Benutzer auf Systemen identifiziert, die TCP-Verbindungen zu anderen Systemen aufgebaut haben. Über eine Ident-Verbindung könnte der ProFTPD daher feststellen, ob der Benutzer, der eine Verbindung zu ihm aufgebaut hat, auch wirklich auf dem System existiert, von dem die Verbindung kommt. Im Jahr 2008 benutzt allerdings niemand mehr ernsthaft Ident, schon gar nicht im Internet, weswegen das Durchführen von Ident-Lookups nur zu einer unnötigen und störenden Verzögerung von mehreren Sekunden beim Verbindungsaufbau zum FTP-Server führt. Deaktivieren Sie dieses Verhalten daher mit der Direktive IdentLookups. Mit den bis hierher beschriebenen Direktiven können Sie einen ProFTPD-Server einrichten, an dem sich auf dem System vorhandene Benutzer anmelden und auf ihr Home-Verzeichnis zugreifen können. Allerdings beherrscht dieser Server noch keine TLS-Verschlüsselung. Diese wird durch das Modul mod_tls bereitgestellt. Unter Ubuntu ist die Konfiguration dieses Moduls in eine eigene Konfigurationsdatei ausgelagert (/etc/proftpd/tls.conf), die über die Direktive Include in der primären Konfigurationsdatei geladen wird: Include /etc/proftpd/tls.conf
Die Datei enthält eine grundsätzlich brauchbare Konfiguration für das Modul mod_tls: TLSEngine TLSRequired TLSLog
SSLv3 /etc/proftpd/proftpd.crt /etc/proftpd/proftpd.key NoCertRequest timeout 300 data 512000
Zunächst wird das Vorhandensein des Moduls mod_tls geprüft. Ist das Ergebnis der Prüfung positiv, wird über die Direktive … TLSEngine
on
… TLS/SSL aktiviert. Die Direktive TLSLog legt die Datei fest, in die SSL-spezifische Daten geloggt werden. Das sind u. a. Angaben zum verwendeten SSL-Protokoll, zu der Cipher-Suite und zum Status einer SSL-Verbindung. Die nächste Direktive … TLSRequired
on
… ist die wichtigste. Damit wird der ProFTPD so konfiguriert, dass er ausschließlich SSL-Verbindungen akzeptiert. Unverschlüsselte Verbindungen werden abgelehnt, so dass kein Benutzer seine Zugangsdaten im Klartext durch die Leitung schicken kann, auch nicht aus Versehen. Achten Sie darauf, dass Sie diese Direktive immer global setzen, nicht nur im Geltungsbereich eines virtuellen Servers. SSL ist nicht immer sicher. Leider akzeptieren viele Dienste heutzutage noch SSL in der Version 2, so auch der ProFTPD. SSL v2 ist allgemein als unsicher eingestuft und sollte unter keinen Umständen verwendet werden. Die Schwächen liegen in der Integritätsprüfung, die über MD5 durchgeführt wird, was potentiell unsicher ist, in der fehlenden Sicherung gegen Manin-the-Middle-Angriffe beim Verbindungsaufbau, in der Möglichkeit, über TCP-Pakete mit gesetztem FIN-Bit Verbindungen vorzeitig zu beenden (Denial-of-Service) und in der Verwendung schwacher Funktionen für den Message Authentication Code (MAC). Aktivieren Sie daher nicht einfach kryptographische Software, ohne zu wissen, was Sie tun. Nicht (sicher) funktionierende Kryptographie ist häufig schlimmer als gar keine Kryptographie, denn sie wiegt den Benutzer in Sicherheit und verleitet ihn dazu, über nicht gesicherte Wege Daten auszutauschen, was er nicht tun würde, wenn er um die Unsicherheit wüsste. Schade, dass der ProFTPD unter Ubuntu in der Standardkonfiguration sowohl SSL v3 als auch SSL v2 akzeptiert. Kompatibilität ist offenbar wichtiger als Sicherheit.
In der Ubuntu-Konfiguration ist SSL v2 erlaubt, daher müssen Sie über die Direktive TLSProtocol das Modul mod_tls so konfigurieren, dass SSL nur in der Version 3 erlaubt ist – so gut wie jeder aktuelle Client beherrscht heutzutage SSL v3.
273
4.6
4
Serverdienste
TLSProtocol
SSLv3
Über die Direktiven TLSRSACertificateFile und TLSRSACertificateKeyFile legen Sie das vom Server zu verwendende Zertifikat und den dazugehörenden privaten Schlüssel fest. Falls Sie ein eigenes Zertifikat verwenden, z. B. über CAcert erstellt, passen Sie die Werte entsprechend an. Ist der private Schlüssel mit einem Passwort geschützt, wird der ProFTPD beim Start danach fragen. SSL bietet nicht nur die Möglichkeit, dass sich ein Server gegenüber den Clients authentifiziert, sondern zusätzlich auch, dass sich Clients über eigene Zertifikate gegenüber dem Server identifizieren. Damit können Sie den ProFTPD so konfigurieren, dass nur Verbindungen von Clients mit von Ihnen ausgestellten Zertifikaten erlaubt sind – ein weiterer Zugewinn an Sicherheit, denn damit entfällt die Möglichkeit, dass sich ein Angreifer über einen Brute-Force-Angriff Zugriff zum Server verschafft. Möchten Sie den ProFTPD so konfigurieren, dass er Client-Zertifikate akzeptiert, können Sie über die Direktive TLSCACertificatePath ein Verzeichnis angeben, in dem sich die Client-Zertifikate samt über das OpenSSL-Programm c_rehash erzeugter Hash-Dateien befinden. Möchten Sie keine Client-Zertifikate verwenden, sollten Sie die Direktive … TLSOptions
NoCertRequest
… gesetzt lassen, da der ProFTPD damit angewiesen wird, bei einem Verbindungsaufbau durch einen Client diesem keine Anfrage nach einem Zertifikat zu schicken. Einige FTP-Clients haben mit dieser Anfrage Probleme und stürzen ab. Die letzte Direktive legt fest, wie häufig die SSL-Parameter einer bestehenden Verbindung zwischen Server und Client neu ausgehandelt werden müssen. In der Standardkonfiguration unter Ubuntu ist dieses Aushandeln deaktiviert, was allerdings den gängigen Regeln für den Einsatz kryptographischer Software widerspricht. Mit den nachstehenden Werten legen Sie fest, dass die SSL-Parameter entweder nach 300 Sekunden oder nach 1 GB Übertragungsvolumen neu ausgehandelt werden. TLSRenegotiate
timeout 300 data 1024000
Nach Abschluss der Konfiguration speichern Sie diese und starten den ProFTPD neu: # sudo /etc/init.d/proftpd restart * Stopping ftp server proftpd * Starting ftp server proftpd
274
Dateitransfer
Anschließend können Sie über einen FTP-Client mit SSL-Unterstützung eine SSLgesicherte Verbindung zum Server aufnehmen. Ein einfach zu bedienender FTPClient mit SSL-Unterstützung ist das Firefox-Plugin FireFTP.18 Sofern Sie kein von einer offiziellen CA signiertes Zertifikat verwenden, wird Ihnen der FTP-Client bei der Verbindung eine bekannte Fehlermeldung anzeigen. Prüfen Sie die Details des Zertifikates, um zu sehen, dass es sich dabei auch wirklich um das zu Ihrem FTP-Server gehörende Zertifikat handelt (Abbildung 4.63).
Abbildung 4.63 SSL-Zertifikat des FTP-Servers
Benutzerverwaltung für FTP Wenn Sie per FTP Dateien und Verzeichnisse für Ihre Website übertragen möchten, ist die einfachste Möglichkeit, das Benutzerkonto zu verwenden, dem das DocumentRoot des Webservers gehört. Unter Ubuntu ist das der Benutzer www-data, unter Gentoo der Benutzer apache. Kurioserweise sind die Dateiberechtigungen in den DocumentRoots beider Distributionen nicht so konfiguriert, dass der Apache-Benutzer schreibend darauf zugreifen darf. Das mag ein Sicherheitsfeature sein, angesichts des wenig ausgeprägten Sicherheitsbewusstseins beider Distributionen ist es aber doch eher ein Bug. Damit Sie mit dem jeweiligen Apache-Benutzer Daten per FTP ins DocumentRoot hochladen können, müssen Sie die Dateirechte erst anpassen.
Unter Ubuntu: # sudo chown -R www-data:www-data /var/www/
Unter Gentoo: # sudo chown -R apache:apache /var/www/
Aus Sicherheitsgründen ist es ratsam, dem Apache-Benutzer keine Shell zu geben. Fügen Sie daher in der Datei /etc/shells die Zeile … /bin/false
… ein, und ändern Sie die Shell des Apache-Benutzers entsprechend: # sudo usermod -s /bin/false
Ein kompromittierter Webserver ermöglicht einem Angreifer somit nicht automatisch das Öffnen einer Shell, und der Benutzer kann sich zwar per FTP am System anmelden, allerdings keine interaktive Shell öffnen. In der Konfigurationsdatei des ProFTPD sollten Sie anschließend noch die folgende Direktive setzen, damit der ProFTPD nur Benutzer akzeptiert, die eine gültige, d. h. in /etc/shells angegebene, Shell besitzen: RequireValidShell on
4.6.2
SCP und SFTP
Neben der sicheren Dateiübertragung über FTPS gibt es mit den Protokollen SCP und SFTP zwei weitere Übertragungsverfahren, die nach dem gegenwärtigen Stand des Wissens als sicher eingestuft werden, dabei aber nicht den Betrieb eines eigenen Serverdienstes vorausetzen, da sie über SSH-Verbindungen laufen und daher lediglich einen SSH-Dienst benötigen. Sofern Sie SSH für die Administration Ihres Servers einsetzen, wären SCP und/oder SFTP daher naheliegendere Möglichkeiten für die Dateiübertragung als FTPS. Letzteres ist dann sinnvoll, wenn viele Benutzer auf den Server zugreifen und große Datenmengen übertragen werden sollen. Darüber hinaus bietet ein Server wie der ProFTPD umfangreiche Möglichkeiten, Benutzerzugriffe zu reglementieren und Sicherheitsfunktionen zu implementieren. SCP und SFTP hingegen sind relativ simple Programme, die komplett auf SSH aufsetzen und serverseitig keine Möglichkeit bieten, Zugriffe zu steuern. So kommt es auch, dass ein Benutzer, der sich per SCP oder SFTP mit einem Server verbindet, grundsätzlich in der gesamten Verzeichnisstruktur navigieren kann, da OpenSSH leider noch immer keine Möglichkeit bietet, Benutzer in ihrem Home-Verzeichnis einzusperren, so wie es beim ProFTPD möglich ist. SCP SCP ist ein sehr simples Protokoll, das lediglich die Möglichkeit zum Kopieren von Dateien über eine SSH-Verbindung bietet. Unter Linux ist der Kommandozeilenclient scp verbreitet, mit dem einzelne Dateien oder Verzeichnisse per SSH übertragen werden können. Unter Windows steht mit dem Programm WinSCP ein grafischer Client zur Verfügung, der sowohl SCP als auch SFTP beherrscht und
276
Dateitransfer
eine komfortable Oberfläche für Dateioperationen zwischen zwei Rechnern bietet. WinSCP steht unter der GPL und kann kostenlos auf der Homepage19 des Projektes heruntergeladen werden. SCP ist relativ spartanisch und kann lediglich Dateien und Verzeichnisse übertragen, ohne die Möglichkeit, Befehle auf dem Server abzusetzen. In Funktion und Syntax entspricht es dem »lokalen« KopierBefehl cp unter Linux. Clients wie WinSCP emulieren über SCP-Befehle eine interaktive Verbindung zum Server. SFTP SFTP bietet im Gegensatz zu SCP eine Verbindung zum Server, über die wie bei einer FTP-Verbindung Befehle auf dem Server abgesetzt werden können. In der Syntax orientiert sich SFTP an FTP, wie eine Ausgabe der zur Verfügung stehenden Befehle auf dem Server zeigt: # sftp kr@localhost Connecting to hardy... kr@hardy's password: sftp> ? Available commands: cd path lcd path chgrp grp path chmod mode path to 'mode' chown own path help get remote-path [local-path] lls [ls-options [path]] ln oldpath newpath lmkdir path lpwd ls [path] lumask umask mkdir path progress put local-path [remote-path] pwd exit quit rename oldpath newpath rmdir path rm path
Change Change Change Change
remote directory to 'path' local directory to 'path' group of file 'path' to 'grp' permissions of file 'path'
Change owner of file 'path' to 'own' Display this help text Download file Display local directory listing Symlink remote file Create local directory Print local working directory Display remote directory listing Set local umask to 'umask' Create remote directory Toggle display of progress meter Upload file Display remote working directory Quit sftp Quit sftp Rename remote file Remove remote directory Delete remote file
19 http://winscp.net/
277
4.6
4
Serverdienste
symlink oldpath newpath version !command ! ? sftp>
Symlink remote file Show SFTP version Execute 'command' in local shell Escape to local shell Synonym for help
Alles, was Sie für SCP und SFTP benötigen, sind ein SSH-Server und ein passender Client. In den folgenden Beispielen wird WinSCP als Client verwendet. Da SCP und SFTP über SSH arbeiten, wird WinSCP bei der ersten Verbindung zum Server die von SSH gewohnte Meldung anzeigen, dass der Host-Key unbekannt ist, und Sie zu einer Aktion auffordern (Abbildung 4.64).
Abbildung 4.64 SSH-Meldung von WinSCP
Wenn Sie sichergehen wollen, dass Sie mit dem richtigen Server verbunden sind, vergleichen Sie den in der Meldung von WinSCP angezeigten Fingerprint des Server-Keys mit dem Fingerprint des Servers. Dazu können Sie auf dem Server das Programm ssh-keygen aufrufen: # ssh-keygen -lf /etc/ssh/ssh_host_rsa_key 2048 a2:7d:45:54:fb:6f:24:ab:2f:bf:59:b2:fb:11:01:1e /etc/ssh/ssh_ host_rsa_key.pub
Nach der erfolgreichen Anmeldung – anmelden kann sich jeder Benutzer, der eine SSH-Verbindung zum Server aufbauen darf – werden Sie das Problem mit SCP und SFTP sehen (Abbildung 4.65). Die SSH-Verbindung verwendet die Shell, die für den jeweiligen Benutzer konfiguriert ist, folglich kann ein Benutzer auf alle Dateien und Verzeichnisse zugreifen, für die es die Shell erlaubt.
278
Dateitransfer
Abbildung 4.65 Zugriff auf den kompletten Verzeichnisbaum
SCPONLY Das Problem des Zugriffs auf den kompletten Verzeichnisbaum über SSH rührt daher, dass der OpenSSH-Server keine Möglichkeit bietet, Benutzer in ihr HomeVerzeichnis einzusperren. Es existieren verschiedene Patches, um OpenSSH um diese Funktionalität zu erweitern, allerdings erfordern diese Lösungen entweder das manuelle Verändern des Quelltextes oder die Installation einer Version von OpenSSH, die nicht aus dem Paketmanager einer Distribution stammt. Das führt dazu, dass eine besonders sicherheitskritische Software nicht über den automatischen Update-Mechanismus gepflegt wird, was keinen erstrebenswerten Zustand darstellt. Auch ist das Betreiben eines zweiten OpenSSH-Servers in einer chrootUmgebung denkbar, doch das ist mit viel Handarbeit verbunden und stellt damit ebenfalls eine eher wenig elegante Lösung dar. Überdies ist chroot entgegen der landläufigen Meinung unter Linux kein Sicherheitsfeature, denn das Ausbrechen aus einer chroot-Umgebung ist trivial, worauf auch die Dokumentation von chroot hinweist. Abhilfe schafft die Pseudo-Shell scponly.20 scponly erlaubt das Einsperren von Benutzern in ihr Home-Verzeichnis, ohne dass dafür der OpenSSH-Server manipuliert werden muss. Obwohl der Name vermuten lässt, dass mit scponly lediglich SCP möglich ist, kann scponly auch für SFTP und RSYNC verwendet werden. 20 http://sublimation.org/scponly/
279
4.6
4
Serverdienste
scponly ist für Ubuntu und Gentoo verfügbar und wird auf beiden Distributionen über den bekannten Weg installiert. Ubuntu: # sudo apt-get install scponly
Gentoo: # sudo emerge scponly
Unter Ubuntu ist nach der Installation noch etwas Handarbeit notwendig. Zum Zeitpunkt der Manuskripterstellung war das für Gentoo verfügbare Paket von scponly (Version 4.8) aufgrund von Problemen mit dem SFTP-Subsystem nicht lauffähig. Die Lösung besteht in einem solchen Fall in viel Detektiv- und Handarbeit oder im Verzicht auf scponly. Ist das Einsperren von Benutzern in ihre HomeVerzeichnisse notwendig, was in der Regel immer der Fall ist, wenn verschiedene Benutzer auf einem System arbeiten, bleibt als Ausweichlösung nur der ProFTPD. Um das Anlegen neuer Benutzer für die Benutzung von scponly zu erleichtern, bringt scponly das Skript setup_chroot.sh mit. Seltsamerweise ist das Skript nach der Installation nicht benutzbar und muss erst entpackt und mit den richtigen Dateirechten versehen werden. # cd /usr/share/doc/scponly/setup_chroot # sudo gzip –d setup_chroot.sh.gz # sudo chmod 700 setup_chroot.sh
Nicht nur das Skript setup_root.sh ist nicht automatisch einsatzbereit, auch das Programm scponlyc, die Shell, mit der ein SSH-Benutzer in seinem Home-Verzeichnis festgenagelt wird, muss noch mit den richtigen Dateirechten, dem SUIDBit, versehen werden: # sudo chmod u+s /usr/sbin/scponlyc
Anschließend können Sie mit dem Skript einen neuen Benutzer anlegen, der über SCP auf den Server zugreifen, dabei aber nicht sein Home-Verzeichnis verlassen kann. Das Anlegen von Benutzern über setup_chroot.sh erfolgt über einen Dialog. Da setup_chroot.sh die Datei config.h aus dem Verzeichnis /usr/share/doc/ scponly/setup_chroot benötigt, müssen Sie zum Ausführen des Skriptes in dieses Verzeichnis wechseln: # sudo ./setup_chroot.sh Next we need to set the home directory for this scponly user. please note that the user's home directory MUST NOT be writeable by the scponly user. this is important so that the scponly user cannot subvert the .ssh configuration parameters.
280
Dateitransfer
for this reason, a writeable subdirectory will be created that the scponly user can write into. -en Username to install [scponly] scpuser -en home directory you wish to set for this user [/home/scpuser] -en name of the writeable subdirectory [incoming] -e creating /home/scpuser/incoming directory for uploading files Your platform (Linux) does not have a platform specific setup script. This install script will attempt a best guess. If you perform customizations, please consider sending me your changes . Look to the templates in build_extras/arch. - joe at sublimation dot org please set the password for scpuser: Enter new UNIX password: ******** Retype new UNIX password: ******** passwd: password updated successfully if you experience a warning with winscp regarding groups, please install the provided hacked out fake groups program into your chroot, like so: cp groups /home/scpuser/bin/groups
Die Suche nach config.h Das Skript setup_chroot.sh benötigt für die fehlerfreie Ausführung die Datei config.h, was das Ausführen von beliebigen Verzeichnissen aus schwierig gestaltet. Unsinnigerweise ist die Datei config.h aber gar nicht notwendig. Wenn Sie das Skript setup_ chroot.sh lieber in ein Verzeichnis im Suchpfad kopieren möchten, z. B. in /usr/local/ bin, müssen Sie lediglich die folgenden Zeilen in dem Skript auskommentieren: if [ echo echo echo echo echo echo exit fi
xscponlyc = x ] || [ ! -f ./config.h ]; then 'your scponly build is not configured for chrooted operation.' 'please reconfigure as follows, then rebuild and reinstall:' './configure --enable-chrooted-binary (... other options)' 1
Nach dieser Änderung läuft das Skript auch ohne die Datei config.h.
Nach Durchlauf des Dialogs ist der neue Benutzer samt seinem Home-Verzeichnis angelegt. Struktur und Dateiberechtigungen dieses Verzeichnisses scheinen auf den ersten Blick befremdlich:
Das Verzeichnis selbst ist für den Benutzer nicht beschreibbar und umfasst verschiedene Unterverzeichnisse, die ausführbare Programme enthalten. Lediglich das Unterverzeichnis incoming ist für den Benutzer beschreibbar. Alte Hasen werden diese Struktur kennen, denn in den grauen Zeiten des Internets war diese Art der Verzeichnisstruktur die einzige Möglichkeit, FTP-Benutzer in ihrem Home-Verzeichnis einzusperren. Alle für die SCP-Kommandos notwendigen Programme sind in den Unterverzeichnissen bin, dev, etc, lib und usr abgelegt. Löschen Sie diese Unterverzeichnisse nicht, ansonsten kann der betroffene Benutzer keine Verbindung mehr zum Server aufbauen. Wenn Sie mit WinSCP oder einem anderen beliebigen SCP-Client eine Verbindung zum SSH-Server aufbauen, sehen Sie diese Verzeichnisstruktur und können lediglich in den Ordner incoming schreiben. Das Verlassen Ihres Home-Verzeichnisses ist – wie gewünscht – nicht möglich.
Abbildung 4.66
282
SCP-Verbindung mit scponly
Dateitransfer
Verzeichnisstruktur von scponly Innerhalb des incoming-Verzeichnisses in seinem Home-Verzeichnis kann ein scponlyBenutzer beliebig Daten anlegen und löschen – das ist sein wirkliches Home-Verzeichnis. Wenn Sie SCP in Verbindung mit scponly zur Datenanlieferung für Ihren Webserver verwenden und direkt ins DocumentRoot schreiben möchten, legen Sie nur das incomingUnterverzeichnis als DocumentRoot fest, nicht das gesamte Home-Verzeichnis. Es gibt keinen Grund, warum die Verzeichnisse bin, dev, etc, lib und usr samt der enthaltenen Dateien über den Apache abrufbar sein sollten. Der Name des incoming-Verzeichnisses ist beim Anlegen eines Benutzers mit setup_ chroot.sh frei wählbar; Sie können also einfach das bereits vorhandene DocumentRoot
als beschreibbares Verzeichnis angeben.
283
4.6
»Linux is a cancer that attaches itself in an intellectual property sense to everything it touches.« Steve Ballmer
5
Optimierung und Monitoring
Optimierung und Monitoring sind für den Serverbetrieb essenziell. Dieses Kapitel zeigt Ihnen, wie Sie Ihren Server optimal einrichten und überwachen.
5.1
Monitoring
Computersysteme besitzen die unangenehme Eigenschaft, zu den unpassendsten Zeiten Fehler zu produzieren. Bei Serversystemen im Internet kommt noch hinzu, dass sie – ebenfalls zu vollkommen unpassenden Zeitpunkten – Ziele von Angriffen werden können. Hardwaredefekte, Lastspitzen aufgrund vorhersehbarer oder nicht vorhersehbarer Ereignisse oder die über einen langen Zeitraum langsam ansteigende Zahl von Besuchern einer Website, die irgendwann das Fass zum Überlaufen und den Webserver zum Stillstand bringt – die Liste der Gründe für das Fehlverhalten eines Servers ist lang. Wenn ein Server nicht nur als Bastelobjekt betrieben wird, ist das Überwachen der wichtigsten Betriebsparameter des Systems daher sehr empfehlenswert. Überwachungstools für Linux gibt es viele. Als Standard haben sich auch im professionellen Bereich der Multi Router Traffic Graffer (MRTG) und Nagios etabliert. Während MRTG ursprünglich für die Visualisierung von Netzwerkverkehr auf Routern entwickelt worden ist und auf SNMP basiert, ist Nagios ein multifunktionales Werkzeug zur Überwachung von Systemen und Infrastrukturen. MRTG und Nagios stehen beide unter der GPL. Beide Programme dienen unterschiedlichen Zwecken. Während Nagios ein Echtzeit-Monitoring-Programm mit verschiedenen Alarmierungsmechanismen ist, stellt MRTG lediglich über SNMP abgerufene Messwerte grafisch dar und erlaubt so eine zeitliche Bewertung dieser Werte, wodurch sich leicht Tendenzen wie z. B. zunehmender Netzwerkverkehr oder schwindender Festplattenplatz erkennen lassen.
285
5
Optimierung und Monitoring
5.1.1
SNMP
Das Simple Network Management Protocol1 (SNMP) ist ein Protokoll der Anwendungsebene und dient zur Überwachung und Steuerung von IT-Systemen. SNMP gehört wahrscheinlich zu den am wenigsten verstandenen und gleichzeitig meistbenutzten Protokollen der IT-Welt. Das Protokoll selbst ist zwar recht simpel und bietet nur wenige Befehle, die Repräsentation von Daten für die Bearbeitung mit SNMP auf einem Host hingegen ist sehr komplex, wenig intuitiv und häufig schlecht dokumentiert. Alle über einen SNMP-Dienst verfügbaren Informationen sind in der Management Information Base (MIB) abgelegt. SNMP erlaubt das Auslesen von Daten von einem System, auf dem ein SNMPDienst läuft, das Ändern von Daten und das Senden von Benachrichtigungen. Über SNMP lassen sich beliebige Informationen auslesen. Das Protokoll selbst legt in dieser Hinsicht keine Beschränkung auf, lediglich die MIB des Agenten muss entsprechende Informationen bereithalten. SNMP ist für so gut wie jede Plattform verfügbar, von Linux über Solaris, Cisco IOS, Windows, kleinen HomeRoutern bis zu Telefon- und Klimaanlagen. Äußerst charmant daran ist, dass sich all diese verschiedenen Plattformen über ein IP-basiertes Protokoll überwachen und steuern lassen, was gerade in kleinen Firmen das Zusammenfassen der administrativen Arbeit ermöglicht. Bei SNMP unterscheidet man zwischen der Station, die Systeme im Netzwerk überwacht, dem Manager, und den überwachten Systemen, den Agenten. Auf einem Agent läuft ein SNMP-Dienst, der über den UDP-Port 161 SNMP-Anfragen des Managers entgegennimmt. Dabei kann der Manager gezielt einen einzelnen Datensatz aus der MIB anfordern (GET), den nächsten Datensatz (GETNEXT) oder mehrere Datensätze (GETBULK). Das Schreiben durch den Manager erfolgt durch den Befehl SET. Der Befehl, mit dem Antworten im SNMP-Protokoll beginnen, ist RESPONSE. Ein Agent kann aktiv Meldungen zum Manager schicken, so genannte Traps. Der Protokollbefehl dazu ist TRAP. Das Senden von Traps erfolgt über den UDP-Port 162. Traps dienen dazu, dass Agenten beim Eintreten von (unvorhergesehenen) Ereignissen proaktiv Meldungen zum Manager schicken können. Durch die Verwendung von UDP ist SNMP ein sehr schlankes Protokoll, das wenig Grundrauschen im Netzwerk erzeugt. Die Festlegung auf die genau definierten Ports 161 und 162 erlaubt darüber hinaus eine einfache Verarbeitung über Firewalls oder VPN-Tunnel. Da UDP ein verbindungsloses Protokoll ist, obliegt es dem jeweiligen Programm, die korrekte Übertragung der Daten zu prüfen und zu gewährleisten.
1 http://tools.ietf.org/html/rfc1157
286
Monitoring
SNMP gibt es mittlerweile in der Version 3. Version 1 und 2 verfügen über keine nennenswerten Sicherheitsmechanismen. Agent und Manager »authentifizieren« sich durch die Übermittlung eines Community-Namens im Klartext. In der Praxis finden sich auch heute noch überwiegend SNMP v1 oder v2, da sich gerade die großen Hersteller von Netzwerkkomponenten sehr zögerlich um die Einführung von SNMP in der Version 3 kümmern, die im Gegensatz zu ihren Vorgängerversionen die Möglichkeit von verschlüsselter Authentifizierung bietet, wenngleich auch ein unsicherer Betriebsmodus möglich ist. Manager
GET
RES
TRAP
Agent
Abbildung 5.1
SNMP-Kommunikationsschema
Ein aktiver SNMP-Dienst ist die Voraussetzung dafür, dass ein System mit MRTG überwacht werden kann. Unter Ubuntu können Sie den SNMP-Dienst mit … # sudo apt-get install snmpd
… installieren. Unter Gentoo mit dem folgenden Befehl: # sudo emerge net-snmp
Unter Ubuntu ist der erste Schritt nach der Installation des SNMP-Dienstes das Anlegen einer SNMP-Community für den lesenden Zugriff. SNMP kennt in den Versionen 1 und 2 den Begriff der Community als rudimentären Authentifizierungsmechanismus. Um lesenden und schreibenden Zugriff zu trennen, gibt es eine Read- und eine Write-Community. In der Datei /etc/snmp/snmpd.conf kommentieren Sie zunächst die folgende Zeile aus: #com2sec paranoid
default
public
Anschließend entfernen Sie das Kommentarzeichen vor der nächsten Zeile und ersetzen den Standard-Community-String »public« durch einen eigenen Namen. Dies ist der Name der Read-Community, d. h., jedes Gerät, das lesend auf den SNMP-Dienst zugreifen möchte, muss den korrekten Read-Community-String kennen. com2sec readonly
default
michnix
287
5.1
5
Optimierung und Monitoring
Die lästigen Standard-Strings Der Community-String ist – bei der Verwendung von SNMP v1 und v2 – der Schlüssel zur SNMP-Kommunikation. So unsicher das Übertragen von Authentifizierungsdaten im Klartext auch ist, in der freien Wildbahn sieht man allzu oft, dass die SNMP-StandardStrings »public« für lesenden und »private« für schreibenden Zugriff verwendet werden. Um ein Mindestmaß an Sicherheit zu garantieren, sollten Sie zumindest diese Werte direkt nach der Installation des SNMP-Dienstes ändern. Strings für die Write-Community sollten Sie gar nicht erst setzen, denn dann kann ein Angreifer nicht schreibend per SNMP auf Ihr System zugreifen.
Bei der Einrichtung von Monitoring-Programmen kann es hilfreich sein, durch manuelle Abfragen Werte in der MIB zu lokalisieren oder zu überprüfen. Ein gutes Programm für die manuelle Abfrage von SNMP-Werten ist MIB Browser, von dem eine kostenlose Version von der Website des Herstellers2 heruntergeladen werden kann. Auch wenn in der Praxis das manuelle Abfragen von SNMPWerten kaum vorkommt, ist es für die Einrichtung von SNMP sehr hilfreich, mit einem geeigneten Werkzeug einen Blick in die MIB des zu überwachenden Gerätes werfen zu können. Der MIB Browser ist in Java geschrieben und für verschiedene Plattformen erhältlich. Wenn Sie den MIB Browser lokal verwenden, also auf dem System, auf dem der SNMP-Dienst läuft, brauchen Sie an diesem Dienst keine Änderungen durchzuführen. Möchten Sie aber über das Netzwerk auf den Dienst zugreifen – was aufgrund der Unsicherheit von SNMP v1 und v2 nicht empfehlenswert ist –, müssen Sie den SNMP-Dienst so umkonfigurieren, dass er über das Netzwerk erreichbar ist. Standardmäßig ist er unter Ubuntu so konfiguriert, dass er nur auf dem lokalen Netzwerk erreichbar ist, was für lokale Agenten wie MRTG (siehe Abschnitt 5.1.2) vollkommen ausreichend ist. Passen Sie in der Datei /etc/default/snmpd die Variable SNMPDOPTS an – löschen Sie in der betreffenden Zeile die lokale IPAdresse 127.0.0.1, und starten Sie den SNMP-Dienst anschließend neu: # sudo /etc/init.d/snmpd restart
Anschließend ist Ihr System auch von extern per SNMP erreichbar. Holzauge, sei wachsam! Nach Durchführen der geplanten Arbeiten, z. B. der Suche nach Werten in der MIB, sollten Sie den Dienst allerdings wieder umkonfigurieren, so dass er von außen nicht mehr erreichbar ist. Zusätzlich sollten Sie die Host-Firewall so konfigurieren, dass alle UDPPakete mit Ausnahme von Antworten auf DNS- und NTP-Anfragen verworfen werden.
2 http://www.ireasoning.com/mibbrowser.shtml
288
Monitoring
Öffnen Sie den MIB Browser, geben Sie den Zielhost und unter Advanced den Community-String ein, und klicken Sie auf den Go-Button. Sobald die Verbindung zum SNMP-Dienst hergestellt ist, können Sie in der Baumansicht links abzufragende Werte auswählen und über das Kontextmenü – rechte Maustaste – abrufen. Alternativ können Sie über den Get-Bulk-Befehl den gesamten MIB-Baum des SNMP-Dienstes abrufen (Abbildung 5.2)
Abbildung 5.2 Browsen im MIB-Baum
Sie können SNMP-Daten auch lokal auf dem Server abfragen. Dazu bringt das Paket snmp einige Kommandozeilenprogramme mit. Mit dem Befehl snmpwalk können Sie beispielsweise die gesamte MIB abfragen: # snmpwalk -v1 -c michnix localhost|more SNMPv2-MIB::sysDescr.0 = STRING: Linux hardy2 2.6.24-16server #1 SMP Thu Apr 10 13:58:00 UTC 2008 i686 SNMPv2-MIB::sysObjectID.0 = OID: NET-SNMP-MIB::netSnmpAgentOIDs.10 DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (286618) 0:47:46.18 SNMPv2MIB::sysContact.0 = STRING: Root (configure /etc/ snmp/snmpd.local.conf) SNMPv2-MIB::sysName.0 = STRING: hardy2 SNMPv2-MIB::sysLocation.0 = STRING: Unknown (configure /etc/snmp/ snmpd.local.conf) SNMPv2-MIB::sysORLastChange.0 = Timeticks: (6) 0:00:00.06 [...]
289
5.1
5
Optimierung und Monitoring
Als Kommandozeilenparameter müssen Sie die gewünschte SNMP-Version angeben, den Community-String und den Host. Möchten Sie gezielt einen Wert abfragen, können Sie das mit snmpget bewerkstelligen, das mit denselben Parametern aufgerufen wird, dazu aber noch den gewünschten Wert übergeben bekommt: # snmpget -v1 -c michnix localhost sysDescr.0 SNMPv2-MIB::sysDescr.0 = STRING: Linux hardy2 2.6.24-16server #1 SMP Thu Apr 10 13:58:00 UTC 2008 i686
Sofern schreibender SNMP-Zugriff konfiguriert ist, können Sie mit snmpset Werte per SNMP auf dem Host verändern: # snmpset -v1 -c michnix localhost sysContact.0 s "Field Support."
Neben Zeichenketten und Zahlen enthält die MIB eines Systems auch Indizes, die Angaben über zusammenhängende Daten enthalten, z. B. eine Übersicht über alle Datenträger eines Systems. Indizes lassen sich mit dem Befehl snmptable abrufen: # snmptable -v1 -c michnix -Cw 100 localhost hrStorageTable SNMP table: HOST-RESOURCES-MIB::hrStorageTable hrStorageIndex hrStorageType hrStorageDescr 1 HOST-RESOURCESTYPES::hrStorageRam Physical memory 3 HOST-RESOURCESTYPES::hrStorageVirtualMemory Virtual memory 6 HOST-RESOURCESTYPES::hrStorageOther Memory buffers 7 HOST-RESOURCESTYPES::hrStorageOther Cached memory 8 HOST-RESOURCESTYPES::hrStorageOther Shared memory 10 HOST-RESOURCESTYPES::hrStorageVirtualMemory Swap space 31 HOST-RESOURCESTYPES::hrStorageFixedDisk [...]
5.1.2
MRTG
Der Multi Router Traffic Grapher MRTG ist ein Programm, das Informationen über ein Host-System per SNMP ausliest und grafisch darstellt. Dabei ist MRTG kein Programm zur Echtzeitüberwachung von Netzwerkkomponenten, das den aktuellen Status eines Systems darstellt und den Administrator über unvorherge-
290
Monitoring
sehene Ereignisse informiert; MRTG ermöglicht eine längerfristige Betrachtung der Betriebsparameter (Abbildung 5.3). Daher wird es häufig dazu verwendet, die Auslastung von Netzwerkschnittstellen, CPU, Speicher oder Festplatten darzustellen.
Abbildung 5.3 MRTG-Darstellung von Messwerten
MRTG ist ursprünglich zur Visualisierung von Netzwerkverkauf auf Router-Interfaces entwickelt worden – daher auch der Name. Dank der Verwendung von SNMP kann MRTG aber so gut wie alle Datenquellen darstellen, die über SNMP abgefragt werden können. Dabei ist das Einpflegen von Nicht-Standardquellen eine mitunter haarige Angelegenheit. Weniger optimistische Zeitgenossen würden es auch als Krankheit bezeichnen. Glücklicherweise bringen sowohl Ubuntu als auch Gentoo fertige Pakete für MRTG mit, so dass die händische Installation entfällt. Die Installation unter Ubuntu ist wie gewohnt einfach. Sofern noch ein SNMPDienst installiert ist, muss dieser im selben Schritt mitinstalliert werden, da MRTG diesen braucht, um Daten vom System abfragen zu können: # sudo apt-get install mrtg snmpd
Nach der Installation finden Sie im DocumentRoot des Apache (/var/www) das Verzeichnis mrtg. Darin legt MRTG die erzeugten Daten ab, so dass sie über den
291
5.1
5
Optimierung und Monitoring
Apache-Webserver zugänglich sind. MRTG wird über den lokalen Cron-Dienst gestartet. Dies ist in der Datei /etc/conf.d/mrtg festgelegt: */5 * * * * root if [ -d /var/lock/mrtg ]; then if [ -x /usr/ bin/mrtg ] && [ -r /etc/mrtg.cfg ]; then env LANG=C /usr/bin/mrtg / etc/mrtg.cfg >> /var/log/mrtg/mrtg.log 2>&1; fi else mkdir /var/ lock/mrtg; fi
In diesem Eintrag finden Sie einen Verweis auf die Konfigurationsdatei von MRTG (/etc/mrtg.cfg). Leider trägt es wenig zur Übersichtlichkeit des Systems bei, dass die Datei direkt unterhalb von /etc liegt und nicht in einem eigenen Unterverzeichnis, nicht zuletzt weil weitere Datenquellen außer der standardmäßig konfigurierten ersten Netzwerkschnittstelle des Systems in eigenen Konfigurationsdateien festgelegt werden. Legen Sie daher direkt nach der Installation von MRTG das Verzeichnis /etc/mrtg an, und verschieben Sie die Konfigurationsdatei in dieses Verzeichnis: # sudo mkdir /etc/mrtg # sudo mv /etc/mrtg.cfg /etc/mrtg/
Anschließend passen Sie den Pfad zur Konfigurationsdatei in der oben beschriebenen Cron-Datei an (/etc/cron.d/mrtg). Die beiden Stellen sind nachfolgend fett markiert. */5 * * * * root if [ -d /var/lock/mrtg ]; then if [ -x /usr/ bin/mrtg ] && [ -r /etc/mrtg/mrtg.cfg ]; then env LANG=C /usr/bin/ mrtg /etc/mrtg/mrtg.cfg >> /var/log/mrtg/ mrtg.log 2>&1; fi else mkdir /var/lock/mrtg; fi
Nach dieser Änderung führt der lokale Cron-Dienst alle fünf Minuten MRTG aus und schreibt das Ergebnis in das Verzeichnis /var/www/mrtg, wo Sie es mit einem Webbrowser einsehen können. Leider sieht das Verzeichnis noch recht karg aus, da MRTG von sich aus keine Indexdatei erzeugt (Abbildung 5.4). Glücklicherweise bringt MRTG das Tool indexmaker mit, mit dessen Hilfe Sie aus den Daten der Konfigurationsdatei eine Indexdatei für den Apache erzeugen können: # indexmaker /etc/mrtg.cfg > /var/www/mrtg/index.html
Im Verzeichnis /var/www befindet sich nach dem Durchlauf die Datei index.html, welche die Tagesansicht der bei der Ausführung von indexmaker angegebenen in der Konfigurationsdatei anzeigt (Abbildung 5.5). Über einen Klick auf die Grafik kommen Sie zur Detailansicht der Datenquelle (Abbildung 5.6).
292
Monitoring
Abbildung 5.4 Das MRTG-Verzeichnis ohne Indexdatei
Abbildung 5.5 MRTG-Indexdatei
293
5.1
5
Optimierung und Monitoring
Abbildung 5.6 Detailansicht der Netzwerkschnittstelle »eth0«
Unter Gentoo installieren Sie für MRTG die folgenden Pakete: # sudo emerge net-analyzer/net-snmp media-libs/gd net-analyzer/mrtg
Anschließend erstellen Sie aus der Beispiel-Konfigurationsdatei des SNMP-Dienstes eine »richtige« Konfigurationsdatei: # sudo cp /etc/snmp/snmpd.conf.example /etc/snmp/snmpd.conf
In dieser Datei ändern Sie die Zeilen mit dem Schlüsselwort com2sec: com2sec local localhost com2sec local 192.168.0.0/24
michnix michnix
Damit legen Sie fest, dass über das lokale Loopback-Interface und über das Netzwerk 192.168.0.0/24 auf den SNMP-Dienst zugegriffen werden kann. Damit der SNMP-Dienst diese Datei auch verwendet, müssen Sie noch in der Datei /etc/ conf.d/snmpd die Flags des Dienstes entsprechend setzen: SNMPD_FLAGS="-C -c /etc/snmp/snmpd.conf"
294
Monitoring
Danach können Sie den Dienst neu starten und so einrichten, dass er beim Systemstart automatisch geladen wird: # sudo /etc/init.d/snmpd restart # sudo rc-update -a snmpd default * snmpd added to runlevel default
Mit snmpget oder snmpwalk können Sie sich davon überzeugen, dass der SNMPDienst läuft und erreichbar ist: # snmpwalk -v1 -c michnix localhost|more SNMPv2-MIB::sysDescr.0 = STRING: Linux gentoo 2.6.19-gentoor5 #1 SMP Wed Apr 4 05:44:43 U TC 2007 i686 SNMPv2-MIB::sysObjectID.0 = OID: NET-SNMP-MIB::netSnmpAgentOIDs.10 DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (51165) 0:08:31.65 SNMPv2-MIB::sysContact.0 = STRING: root SNMPv2-MIB::sysName.0 = STRING: gentoo SNMPv2-MIB::sysLocation.0 = STRING: Footown SNMPv2-MIB::sysORLastChange.0 = Timeticks: (0) 0:00:00.00 SNMPv2-MIB::sysORID.1 = OID: SNMP-FRAMEWORKMIB::snmpFrameworkMIBCompliance SNMPv2-MIB::sysORID.2 = OID: SNMP-MPD-MIB::snmpMPDCompliance SNMPv2-MIB::sysORID.3 = OID: SNMP-USER-BASED-SMMIB::usmMIBCompliance SNMPv2-MIB::sysORID.4 = OID: SNMPv2-MIB::snmpMIB SNMPv2-MIB::sysORID.5 = OID: TCP-MIB::tcpMIB SNMPv2-MIB::sysORID.6 = OID: IP-MIB::ip [...]
Um MRTG zu konfigurieren, erstellen Sie sowohl das Verzeichnis /etc/mrtg, in dem die Konfigurationsdateien von MRTG abgelegt werden, als auch das Verzeichnis /var/www/localhost/htdocs/mrtg, wo MRTG die HTML-Seiten samt der dazugehörenden Grafiken ablegt: # sudo mkdir /etc/mrtg # sudo mkdir /var/www/localhost/htdocs/mrtg
Die Konfigurationsdateien werden unter Gentoo analog zu denen unter Ubuntu erstellt, Gleiches gilt für den Cron-Job. Mit dieser Konfiguration haben Sie eine Darstellung des Netzwerkverkehrs, der über die primäre Schnittstelle Ihres Systems läuft. MRTG stellt den Verkehr getrennt nach eingehendem und ausgehendem Verkehr dar und zeigt vier verschiedene Graphen:
295
5.1
5
Optimierung und Monitoring
왘
eine Tagesübersicht, basierend auf den Werten, die alle fünf Minuten aus dem Cron-Job ermittelt werden,
왘
eine Wochenübersicht, basierend auf dem 30-Minuten-Durchschnitt der Messdaten,
왘
eine Monatsübersicht, basierend auf dem 2-Stunden-Durchschnitt der Messdaten, und
왘
eine Jahresübersicht, basierend auf dem Tagesdurchschnitt der Messdaten.
Die Übersichten über diese vier Zeiträume geben dem Administrator eine sehr gute Informationsquelle zur Tendenzentwicklung. Kurzfristige Lastspitzen und Performance-Engpässe lassen sich aus der Tages- und Wochenübersicht ermitteln, die langfristige Entwicklung ergibt sich aus der Monats- und Jahresübersicht. Wenn sich ein System kurzfristig an Leistungsgrenzen bewegt – abzulesen in der Tagesübersicht –, kann das auf einmalige Ereignisse wie z. B. Marketingaktionen oder Angriffe zurückzuführen sein und muss kein Grund sein, das System aufzurüsten. Zeigt sich anhand der langfristigen Daten allerdings, dass ein System ständig unter Dampf steht, ist eine Aufrüstung angeraten. Das Layout der Indexseite können Sie über entsprechende Parameter des Programms indexmaker verändern: # indexmaker Usage: indexmaker [options] mrtg.cfg [other.cfg ...] [...]
Die auf der Detailseite angezeigten Werte werden über die Konfigurationsdatei /etc/mrtg/mrtg.cfg gesteuert. Deren Inhalt wird – sofern bei der Installation nicht automatisch geschehen – mit dem Befehl cfgmaker erzeugt: # sudo cfgmaker michnix@localhost > /etc/mrtg/mrtg.cfg
Die mit diesem Befehl erzeugte Datei ist ein gutes Beispiel für die Gestaltungsmöglichkeiten von MRTG: WorkDir: /var/www/mrtg EnableIPv6: no Target[hardy.eth0]: #eth0:michnix@localhost: SetEnv[hardy.eth0]: MRTG_INT_IP="192.168.0.20" MRTG_INT_DESCR="eth0" MaxBytes[hardy.eth0]: 1250000 Title[hardy.eth0]: eth0 PageTop[hardy.eth0]:
Neben den Angaben, in welchem Verzeichnis MRTG die erzeugten Daten ablegen soll, finden sich in der Datei auch Angaben, die auf der Detailseite ausgegeben werden, sowie Formatierungsangaben im HTML-Format. Dadurch ist es möglich, eine individuell gestaltete Ausgabe zu erzeugen, was insbesondere dann hilfreich ist, wenn MRTG nicht nur vom Serverbetreiber selbst, sondern auch von Kunden oder Mitarbeitern genutzt wird. Aussagekräftige MRTG-Seiten sind dann extrem nützlich. So können Sie durch Einfügen von beliebigen HTML-Codes die Informationen formatieren und benutzerfreundlich gestalten (Abbildung 5.7): [...] PageTop[localhost_eth0]:
Neben dem Überwachen des Netzwerkverkehrs sind bei einem Server noch weitere Betriebsparameter von großem Interesse, z. B. die CPU-Last und der Speicherverbrauch. Leider ist cfgmaker nicht so mächtig, diese Werte selbständig in eine Konfigurationsdatei schreiben zu können, weswegen Sie die gewünschten Werte händisch in der MIB des Systems suchen und in eine Konfigurationsdatei verpacken müssen. Eine Konfigurationsdatei zur Überwachung der CPU, aufgeteilt in Benutzer- und Kernelzeiten, ist die folgende: WorkDir: /var/www/mrtg LoadMIBs: /usr/share/snmp/mibs/UCD-SNMP-MIB.txt Target[hardy.cpu]:ssCpuRawUser.0&ssCpuRawUser.0:[email protected]+ s sCpuRawSystem.0&ssCpuRawSystem.0:[email protected]+ssCpuRawNice.0&ss CpuRawNice.0:[email protected]
298
Monitoring
RouterUptime[hardy.cpu]: [email protected] MaxBytes[hardy.cpu]: 100 Title[hardy.cpu]: CPU Load on hardy PageTop[hardy.cpu]:
Active CPU Load %
Unscaled[hardy.cpu]: ymwd ShortLegend[hardy.cpu]: % YLegend[hardy.cpu]: CPU Utilization Legend1[hardy.cpu]: Active CPU in % (Load) Legend2[hardy.cpu]: Legend3[hardy.cpu]: Legend4[hardy.cpu]: LegendI[hardy.cpu]: Active LegendO[hardy.cpu]: Options[hardy.cpu]: growright,nopercent
Denken Sie daran, den Community-String anzupassen, und speichern Sie die vorstehende Konfiguration in die Datei /etc/mrtg/cpu.cfg. In einer weiteren Konfigurationsdatei können Sie die Überwachung des Speicherverbrauchs festlegen: LoadMIBs: /usr/share/snmp/mibs/HOST-RESOURCES-MIB.txt Target[hardy.mem]: .1.3.6.1.4.1.2021.4.6.0&.1.3.6.1.4.1.2021.4.6.0:\ michnix@localhost PageTop[hardy.mem]:
Free Memory
WorkDir: /var/www/mrtg Options[hardy.mem]: nopercent,growright,gauge,noinfo Title[hardy.mem]: Free Memory on hardy MaxBytes[hardy.mem]: 1000000 kMG[hardy.mem]: k,M,G,T,P,X YLegend[hardy.mem]: bytes ShortLegend[hardy.mem]: bytes LegendI[hardy.mem]: Free Memory: LegendO[hardy.mem]: Legend1[hardy.mem]: Free memory, not including swap, in bytes
Speichern Sie diese Datei als /etc/mrtg/mem.cfg. Damit MRTG diese Konfigurationsdateien verwendet, müssen Sie anschließend in der Datei /etc/cron.d/mrtg die entsprechenden Einträge anlegen: */5 * * * * root if [ -d /var/lock/mrtg ]; then if [ -x /usr/ bin/mrtg ] && [ -r /etc/mrtg/mem.cfg ]; then env LANG=C /usr/bin/ mrtg /etc/mrtg/mem.cfg >> /var/log/mrtg/ mrtg.log 2>&1; fi else mkdir /var/lock/mrtg; fi */5 * * * * root if [ -d /var/lock/mrtg ]; then if [ -x /usr/ bin/mrtg ] && [ -r /etc/mrtg/cpu.cfg ]; then env LANG=C /usr/bin/ mrtg /etc/mrtg/cpu.cfg >> /var/log/mrtg/ mrtg.log 2>&1; fi else mkdir /var/lock/mrtg; fi
299
5.1
5
Optimierung und Monitoring
Zentrale oder dezentrale Konfiguration Bei MRTG ist eine Aufteilung der Konfiguration auf verschiedene Konfigurationsdateien – eine pro zu überwachendem Wert – durchaus sinnvoll. Ein Fehler in der Konfigurationsdatei kann dazu führen, dass MRTG stillschweigend keine Daten mehr aufzeichnet, was sich nachhaltig in der grafischen Darstellung niederschlägt: Bis der Fehler erkannt und behoben ist, fehlen schlichtweg die Daten in der Übersicht – und sie können auch nicht im Nachhinein wiederhergestellt werden. Daher sollten Sie als funktionierend bekannte Konfigurationen in eigene Dateien schreiben, so dass Änderungen an einzelnen Konfigurationen oder das Hinzufügen neuer Messwerte nicht zum Ausfall der gesamten Datenaufzeichnung von MRTG führen.
Nach dem Schreiben der MRTG- und Cron-Konfiguration wird sich das MRTGVerzeichnis im DocumentRoot mit Dateien füllen: [12:52:36] --- kr@hardy:/var/www/mrtg # ls hardy.cpu-day.png hardy.mem.log month.png hardy.cpu.html hardy.mem-month.png hardy.cpu.log hardy.mem.old hardy.cpu-month.png hardy.mem-week.png hardy.cpu.old hardy.mem-year.png hardy.cpu-week.png index.html hardy.cpu-year.png localhost_eth0-day.png hardy.mem-day.png localhost_eth0.html hardy.mem.html localhost_eth0.log
Um eine übersichtliche Darstellung zu erhalten, können Sie mit dem Programm indexmaker eine neue Indexdatei erstellen. Übergeben Sie dazu als Parameter alle MRTG-Konfigurationsdateien: # indexmaker /etc/mrtg/mrtg.cfg /etc/mrtg/cpu.cfg /etc/mrtg/ mem.cfg > /var/www/mrtg/index.html
Die auf diese Weise erzeuge Indexdatei enthält alle Datenquellen, die in den als Parameter an indexmaker übergebenen Konfigurationsdateien definiert sind (Abbildung 5.8). Durch Klicken auf eine der Grafiken kommen Sie zur Detailansicht der gewählten Datenquelle.
300
Monitoring
Abbildung 5.8
5.1.3
Eine eigene MRTG-Indexdatei
Nagios
MRTG ist gut dafür geeignet, Tendenzen festzustellen und darauf aufbauend Probleme wie Lastspitzen im Nachhinein erkennen und mittel- bis längerfristige Kapazitätsplanungen durchführen zu können. Wofür es sich gar nicht eignet, ist die Echtzeitüberwachung von Systemen oder Infrastrukturen. Um Probleme möglichst zeitnah erkennen und entsprechend reagieren zu können, empfiehlt sich die Verwendung von Tools wie Nagios. Nagios ist ein Client/Server-basiertes Monitoring-Tool, das auf dem zentralen Überwachungsserver Daten von zu überwachenden Systemen sammelt, auswertet, darstellt und auch die Möglichkeit bietet, über Eskalationsketten beim Eintreten von Problemen Systemverantwortliche zu benachrichtigen. Nagios ist Open Source und steht unter der GPL. Daher kann es sehr leicht an eigene Bedürfnisse angepasst werden. Das Herzstück von Nagios ist der Nagios-Daemon selbst. Dieser leistet die gesamte Verwaltungsarbeit des Systems und verarbeitet alle Daten. Die Überwachung selbst wird über Plugins realisiert. Das können Programme oder Skripte sein, die der Nagios-Server aufruft und die über eine definierte Schnittstelle die Ergebnisse ihrer Überwachungstätigkeit an den Nagios-Server zurückmelden.
301
5.1
5
Optimierung und Monitoring
Der Nagios-Server bereitet die Daten – genau wie MRTG – so auf, dass sie über einen (Apache-)Webserver veröffentlicht werden können. Die Weboberfläche von Nagios bietet einem Administrator die Möglichkeit, Befehle an den NagiosServer abzusetzen, z. B. um einen Überprüfungsvorgang unmittelbar auszuführen oder um für einen Host oder einen Dienst eine geplante Downtime einzutragen. Nagios kennt zwei grundsätzliche Möglichkeiten, Überwachungsaktionen auszuführen: Abfragen über das Netzwerk, um die Erreichbarkeit und Güte von Netzwerkdiensten zu ermitteln, und Abfragen auf den zu überwachenden Systemen selbst. Die Prüfungen über das Netzwerk werden über Plugins realisiert, die sich auf dem Nagios-Server befinden und von diesem selbst aufgerufen werden. Mögliche Testfälle sind z. B. die Erreichbarkeit von Systemen per ICMP (»Ping«), das Prüfen, ob ein Webserver erreichbar ist, etc. Da es sich bei den Plugins um Programme handelt, die bis auf den Rückgabewert beliebige Funktionen enthalten können, steht Ihrer Kreativität zur Überwachung Ihres Servers nichts im Weg. Administrator
Apache
CMD
NSCA NSCA Nagios NRPE
NRPE
CPU
WWW
Plugins ICMP
RAM
Nagios Server Überwachtes System
Abbildung 5.9
Übersicht über die Nagios-Komponenten
Um Ressourcen überwachen zu können, die über das Netzwerk nicht erreichbar sind, gibt es zwei verschiedene Agenten, die auf den zu überwachenden Systemen installiert sein müssen, mit denen der Nagios-Server über das Netzwerk kommunizieren und über die er die betreffenden Systeme überwachen kann. Dabei gibt es zwei verschiedene Arten der Überwachung. Das Nagios-Plugin NRPE, der Nagios Remote Plugin Executor, ist ein auf den zu überwachenden Systemen installierter Dienst, der über das Netzwerk Befehle vom Nagios-Server entgegennimmt, lokale Plugins ausführt und die Ergebnisse an den Nagios-Server zurückgibt. Der Verbindungsaufbau findet hierbei vom Nagios-Server in Richtung des zu überwachenden Systems statt, was aus Sicherheitsgründen die »richtige«
302
Monitoring
Richtung ist, denn wenn sich der Nagios-Server in einem internen Netzwerk befindet, ist es kaum wünschenswert, dass die zu überwachenden Systeme Verbindungen zu dem Nagios-Server aufbauen dürfen – vom Internet in ein internes Netz. Der Abschnitt »NRPE« (Seite 323) zeigt die Konfiguration und Verwendung von NRPE. Diese Kommunikationsrichtung stellt das zweite Überwachungs-Plugin für Nagios bereit, das NSCA (Nagios Service Check Acceptor). Dabei läuft ein NSCADienst auf dem zu überwachenden System und baut aktiv Verbindungen zum Nagios-Server auf. Details zur Verwendung von NSCA enthält der entsprechende Abschnitt auf Seite 329. Eine Übersicht über die Architektur von Nagios inklusive der Kommunikationsrichtungen zeigt Abbildung 5.9. Nagios kennt bei der Überwachung zwei unterschiedliche Dinge: Objekte und Services. Hosts sind die Bezeichnung für Systeme, Services stehen für Dienste, die von den Hosts angeboten werden. Ein Host kann verschiedene Services anbieten, z. B. Web, SSH, FTP, Jabber etc. Umgekehrt kann ein Service aber auch von mehreren Hosts angeboten werden. Wenn Ihre Webseite aus Lastgründen auf verschiedene Server verteilt ist und über einen Loadbalancer angesprochen wird, stellt sie zwar einen einzelnen Dienst dar, dieser ist aber von mehreren Hosts abhängig. Hosts und Services können untereinander Abhängigkeiten bilden. Wenn Sie mit Nagios auf einem Host A den Service »Apache« überwachen, der wiederum den Service »Webseite« betreibt, führt ein Ausfall des Dienstes »Apache« dazu, dass auch der Dienst »Webseite« ausfällt. Umgekehrt bedeutet ein Ausfall des Dienstes »Webseite« nicht zwangsläufig, dass der Dienst »Apache« ausgefallen ist. Der Apache-Prozess kann durchaus noch vorhanden sein und von Nagios erkannt werden, trotzdem beantwortet er aber aufgrund eines internen Fehlers keine Anfragen von Clients mehr. Beide Dienste, »Apache« und »Webseite«, liegen auf einem Server, einem von Nagios ebenfalls überwachten Host. Fällt nun dieser Host aus, fallen ebenso beide Dienste aus. Der umgekehrte Fall, dass einer oder beide Dienste ausfallen, führt wiederum nicht dazu, dass der Host ausfällt (siehe Abbildung 5.10). Host
Webseite Nagios Apache
Abbildung 5.10
Abhängigkeiten in Nagios
303
5.1
5
Optimierung und Monitoring
Um solche Gegebenheiten zu modellieren, bietet Nagios die Möglichkeit, Abhängigkeiten von Hosts und Services zu definieren. Nagios selbst ist so schlau, beim Ausfall eines Services zu prüfen, ob der Host, auf dem der Service läuft, noch erreichbar ist. Ist dies nicht der Fall, werden alle dem Host zugeordneten Services als ausgefallen markiert. Die Überprüfung eines Hosts oder Dienstes kann einen von vier Status annehmen: OK, WARNING, CRITICAL, UNKOWN. Dabei sind die Bedeutungen der einzelnen Status die folgenden: 왘
OK: Das Ergebnis der Überprüfung lag innerhalb der erlaubten Parameter.
왘
WARNING: Das Ergebnis der Überprüfung lag über dem für dieses Objekt konfigurierten Schwellwert für den Alarmzustand, aber unterhalb des Schwellwertes für den kritischen Zustand.
왘
CRITICAL: Das Ergebnis der Überprüfung lag über dem für dieses Objekt konfigurierten Schwellwert für den kritischen Zustand.
왘
UNKOWN: Die Prüfung hat einen unbekannten Rückgabewert geliefert, was entweder an einem Fehler in der Ausführung, einem fehlerhaften Plugin oder anderen nicht näher definierten Ereignissen liegen kann. In diesem Fall ist ein Blick in die Logdatei von Nagios angezeigt.
In einer Infrastruktur hängen nicht nur Services von Hosts ab, sondern auch Hosts von anderen Hosts. Webserver können von Loadbalancern abgeschirmt werden, die gesamte Infrastruktur kann sich hinter Firewalls, Routern, Switchen und anderen Netzwerkkomponenten verbergen etc. Vorausgesetzt, dass alle Komponenten einer Infrastruktur mit Nagios überwacht werden, können auch solche Abhängigkeiten modelliert werden. Fällt dann ein Host aus, der andere, von ihm abhängige Hosts abschirmt, markiert Nagios direkt alle diese Hosts als nicht erreichbar. Auf diese Weise lassen sich auch bei größeren Ausfällen die Ursachen ermitteln, und insbesondere bei stark vernetzten Diensten – wie z. B. auf verschiedene Systeme verteilte Web-, Datenbank- und Applikationsserver – ist diese Art der Intelligenz enorm hilfreich, um Probleme lokalisieren zu können. Abbildung 5.11 zeigt eine Kette von Abhängigkeiten. Der eigentliche zu überwachende Dienst ist die vom Webserver WWW ausgelieferte Webseite. Diese ist allerdings von einer Reihe anderer Services und Hosts abhängig. Damit dieser Dienst erreicht werden kann, müssen die Firewall, der Loadbalancer, die Web Application Firewall (WAF), der Switch und der Webserver im Status OK sein. Nur dann ist gewährleistet, dass die Webseite erreichbar ist. Erreichbarkeit ist nicht alles, eine Webseite soll auch Inhalte anbieten. In diesem Beispiel kommen die Inhalte dynamisch aus der auf dem Host DB liegenden Datenbank. Dort holt sie der Application Server APP und reicht die Ergebnisse an
304
Monitoring
den Webserver weiter. Das bedeutet, dass der Service »Webseite« inhaltlich nur dann OK ist, wenn sich die entsprechenden Services auf den Hosts DB und APP im Status OK befinden. Der Ausfall von einem der beiden Hosts, DB oder APP, führt zwar nicht dazu, dass der Dienst »Webseite« nicht mehr erreichbar ist, allerdings kann der Webserver keine sinnvollen Inhalte mehr darstellen.
Nagios
Firewall
Load balancer
WAF
Switch
DB
WWW
APP
Abbildung 5.11
Komplexere Abhängigkeiten in Nagios
Bei der Überprüfung von Services nimmt Nagios in der Regel den Standpunkt eines Benutzers ein. Der Nagios-Server prüft per Netzwerk die Verfügbarkeit von Diensten. Das kann z. B. das Abrufen einer Webseite sein, ein Verbindungsaufbau zu einem FTP-Server etc. Die Verfügbarkeit von Diensten ist in der Regel von großer Bedeutung. Neben den Diensten, die Nagios aus dem Blickwinkel des Benutzers prüft, werden auf den zu überwachenden Hosts lokale Plugins ausgeführt, die beliebige Parameter wie z. B. CPU-Last, Festplattenbelegung, Speicherverbrauch, aktive Prozesse etc. auslesen und an den Nagios-Server berichten.
305
5.1
5
Optimierung und Monitoring
Nagios und der eigene Server Wenn Sie nur einen einzelnen Server betreiben, stellt sich die Frage nach dem sinnvollsten Ort einer Nagios-Installation. Um die Verfügbarkeit des Servers zu überwachen, ist es wenig ratsam, Nagios auf dem zu überwachenden System zu installieren. Fällt das System aus, können Sie auch nicht mehr auf Nagios zugreifen, um nach den Ursachen des Ausfalls zu suchen. Überdies können Sie auf diese Weise auch keine temporären Probleme erkennen. Sie sollten Nagios – so wie jedes Überwachungstool – auf einem eigenen System, idealerweise außerhalb der Infrastruktur installieren, in der Sie den zu überwachenden Server betreiben. Bei der Überwachung einzelner Systeme ist Nagios recht anspruchslos, was seinen Ressourcenbedarf angeht, daher kann für diesen Zweck auch das Anmieten eines günstigen V-Servers bei einem anderen Provider ausreichend sein. Entsprechende Angebote sind schon für unter 10,– € im Monat zu haben. Die in den folgenden Abschnitten gezeigten Beispiele setzen eine Installation von Nagios auf einem externen System voraus.
Installation unter Ubuntu Die Unterstützung von Nagios unter Ubuntu ist sehr umfangreich. Eine Suche nach Nagios-Paketen ergibt eine recht lange Liste: # apt-cache search nagios| awk ' { print $1}' nagios-plugins-basic nagios-plugins-standard arrayprobe libnagios-object-perl mailping nagcon nagios-images nagios-nrpe-plugin nagios-nrpe-server nagios-plugins nagios-plugins-extra nagios-snmp-plugins nagios-statd-client nagios-statd-server nagiosgrapher ndoutils-doc ndoutils-nagios2-mysql nsca munin nagios2 nagios2-common nagios2-dbg nagios2-doc
Die Installationsroutine richtet direkt eine Konfiguration für den Apache-Server ein und startet diesen neu, so dass Sie theoretisch ohne Umwege auf die NagiosOberfläche zugreifen können. Allerdings ist diese über die Basic-Authentifizierung des Apache geschützt, was in der Datei /etc/apache2/conf.d/nagios.conf festgelegt ist: AuthUserFile /etc/nagios2/htpasswd.users
Interessanterweise existiert die Datei /etc/nagios2/htpasswd.users aber gar nicht, so dass Sie diese nach der Installation händisch erzeugen müssen. Verwenden Sie dazu das Apache-Tool htpasswd: # sudo htpasswd -c htpasswd.users nagios New password: ******** Re-type new password: ******** Adding password for user nagios
Ab jetzt ist Nagios über den Webserver im Verzeichnis /nagios2 erreichbar (Abbildung 5.12).
Abbildung 5.12
Die Nagios-Startseite unter Ubuntu
307
5.1
5
Optimierung und Monitoring
Installation unter Gentoo Auch unter Gentoo existiert ein Nagios-Paket. Gemeinsam mit diesem Paket werden auch die weiteren benötigten Pakete installiert. # sudo emerge nagios
Im Anschluss an die Installation müssen Sie den Nagios-Dienst noch für den automatischen Start einrichten: # sudo rc-update add nagios default * nagios added to runlevel default
Damit der Apache automatisch für den Betrieb von Nagios konfiguriert wird, müssen Sie im nächsten Schritt in der Datei /etc/conf.d/apache2 die Variable APACHE_OPTS um den Parameter -D NAGIOS erweitern: APACHE2_OPTS="-D DEFAULT_VHOST -D INFO -D LANGUAGE -D SSL -D SSL_ DEFAULT_VHOST -D PHP5 -D JK -D NAGIOS"
Nach einem Neustart des Apache … # sudo /etc/init.d/apache2 restart
… ist die Nagios-Oberfläche über den Webserver im Verzeichnis /nagios erreichbar (Abbildung 5.13).
Abbildung 5.13
308
Die Nagios-Startseite unter Gentoo
Monitoring
Konfiguration Im Anschluss an die Installation unter Ubuntu und Gentoo ist Nagios zwar über den Apache erreichbar, ohne Konfiguration aber ziemlich nutzlos. Die Installation stellt nur den geringsten Teil der Arbeit zur Einrichtung von Nagios dar. Der größte Teil besteht in der Konfiguration von Nagios. Diese ist unabhängig von der verwendeten Distribution, der einzige Unterschied zwischen Ubuntu und Gentoo besteht darin, dass sich unter Ubuntu die Konfigurationsdateien von Nagios im Verzeichnis /etc/nagios2 befinden, unter Gentoo im Verzeichnis /etc/nagios. Die folgenden Beispiele und Anweisungen verwenden die Pfadangaben von Ubuntu – für eine Adaption nach Gentoo brauchen Sie einfach nur den Pfad /etc/nagios verwenden. Nagios ist so konfiguriert, dass es beim Start die Datei /etc/nagios2/nagios.cfg einliest. Die Datei ist von Hause aus vorbildlich dokumentiert und unter Ubuntu bereits so angepasst, dass kaum mehr Anpassungen notwendig sind. Wichtig sind die Direktiven, in denen die Verzeichnisse festgelegt sind, in denen Nagios nach weiteren Konfigurationsdateien sucht. Wie der Apache kann auch Nagios verschiedene Konfigurationsdateien verwenden, dies muss lediglich in der zentralen Konfigurationsdatei entsprechend konfiguriert sein. Insbesondere sind das die folgenden beiden Direktiven: cfg_dir=/etc/nagios2/conf.d cfg_dir=/etc/nagios-plugins/config
Die Direktiven nagios_user und nagios_group legen den Betriebssystembenutzer fest, in dessen Kontext der Nagios-Server läuft. Alle anderen Direktiven sind für den Anfang unwichtig. In der Hauptsache werden damit globale Vorgaben für das Verhalten von Nagios festgelegt, Logdateien definiert etc. Für die Überwachung eines oder einiger weniger Systeme gibt es in der Regel keinen Grund, an den Standardeinstellungen etwas zu ändern – es sei denn, Sie sind experimentierfreudig oder der Nagios-Server läuft auf einer Maschine mit begrenzten Ressourcen und erfordert Feintuning. Nach dem Start von Nagios können Sie zwar die Startseite aufrufen, das Abfragen von Informationen schlägt allerdings fehl (Abbildung 5.14). Der Grund liegt darin, dass ein nicht näher spezifizierter Benutzer in der Grundkonfiguration von Nagios zwar die Startseite aufrufen darf, aber auch nur diese und nicht mehr. Nagios verwendet zur Identifizierung eines Benutzers das Authentifizierungsverfahren des Apache, d. h. den Benutzer, der nach der Installation mit htpasswd angelegt worden ist und mit dem man sich beim Zugriff auf das Nagios-Verzeichnis am Apache anmelden muss. Damit dieser Benutzer Zugriffsrechte auf die eigentlichen Informationen von Nagios erhält, müssen in der Datei /etc/nagios2/cgi.cfg
309
5.1
5
Optimierung und Monitoring
die entsprechenden Direktiven angepasst werden. Standardmäßig heißt der Benutzer unter Ubuntu nagiosadmin. Damit der nach der Installation angelegte Benutzer nagios zugreifen darf, müssen die folgenden Direktiven geändert werden: authorized_for_system_information=nagios authorized_for_configuration_information=nagios authorized_for_system_commands=nagios authorized_for_all_services=nagios authorized_for_all_hosts=nagios authorized_for_all_service_commands=nagios authorized_for_all_host_commands=nagios
Abbildung 5.14
Fehler beim Zugriff auf Informationen
Damit erhält der Benutzer nagios Zugriff auf alle Host- und Service-Informationen und darf zusätzlich über die Nagios-Oberfläche Befehle absetzen – was später noch näher erläutert wird. Nach dem Neustart des Nagios-Servers … # sudo /etc/init.d/nagios2 restart
… ist ein Zugriff auf alle Informationen möglich (Abbildung 5.15). Freundlicherweise ist Nagios standardmäßig schon so konfiguriert, dass einige Checks auf dem
310
Monitoring
lokalen Host, dem Nagios-Server, ausgeführt werden. Die Checks und ihre Ergebnisse sollten selbsterklärend sein. Darüber hinaus prüft Nagios die Erreichbarkeit des Gateways mit ICMP-Paketen. Sofern das Gateway bei Ihnen erreichbar ist und keiner der überwachten Dienste auf dem Nagios-Server ein Problem hat, sollten alle Status ausschließlich grün sein.
Abbildung 5.15
Service-Details für den lokalen Host
Das Konfigurationsprinzip von Nagios erschließt sich aus der Analyse der vorhandenen Konfigurationsdateien im Verzeichnis /etc/nagios2/conf.d. Auch hier gilt, dass die Konfiguration auch in eine einzelne Datei zusammengefasst werden kann, aus Gründen der Übersichtlichkeit empfiehlt sich aber eine klare Trennung. Die Konfiguration von Nagios umfasst die Definition von Hosts, Services, Hostgruppen, Servicegruppen, Kontaktpersonen, Eskalationsketten und Betriebszeiten. Diese Themen sind in den folgenden Dateien konfiguriert: 왘
contacts_nagios2.cfg: Kontakte und Eskalationsketten
왘
host-gateway_nagios2.cfg: Das Gateway des lokalen Netzes
왘
services_nagios2.cfg: Definition von Services
왘
extinfo_nagios2.cfg: Erweiterte Informationen zu Hosts
311
5.1
5
Optimierung und Monitoring
왘
hostgroups_nagios2.cfg: Hostgruppen
왘
timeperiods_nagios2.cfg: Zeiträume für Überprüfungen
왘
generic-host_nagios2.cfg: Template eines generischen Hosts
왘
generic-service_nagios2.cfg: Template eines generischen Services
왘
localhost_nagios2.cfg: Konfiguration des lokalen Hosts
Templates In der vorstehenden Übersicht ist Ihnen der Begriff Template begegnet. Nagios verwendet zur Konfiguration Objekte, die Eigenschaften an andere Objekte vererben oder Eigenschaften von anderen Objekten erben können. Die Templates für den generischen Host und den generischen Service sind Beispieltemplates, die als Vorlage für die Erstellung eigener Templates dienen können.
Einen guten Einstieg in das Verständnis der Nagios-Konfiguration bietet die automatisch angelegte Konfigurationsdatei für das Gateway des lokalen Netzes (/etc/ nagios2/conf.d/host-gateway_nagios2.cfg): define host { host_name alias address use }
gateway Default Gateway 192.168.0.1 generic-host
Objektdefinitionen in Nagios bestehen stets aus dem Schlüsselwort define, gefolgt vom Typ des Objektes und den Eigenschaften des Objektes, letztere in geschweiften Klammern eingeschlossen. In diesem Fall ist das definierte Objekt ein Host. Dieser Host hat den Namen gateway, der alias dient der besseren Übersichtlichkeit in der Anzeige, die Eigenschaft address legt die IP-Adresse des Hosts fest und das Schlüsselwort use benennt ein Template, das für die Definition des Hosts verwendet wird, in diesem Fall das Template generic-host. Dieses Template ist in der Datei /etc/nagios2/conf.d/generic-host_nagios2.cfg definiert: define host{ name notifications_enabled event_handler_enabled flap_detection_enabled failure_prediction_enabled process_perf_data retain_status_information retain_nonstatus_information
Die in diesem Template festgelegten Eigenschaften werden von allen Hosts übernommen, die das Template über die use-Direktive verwenden. Änderungen am Template wirken sich unmittelbar auf alle Hosts aus, die dieses Template verwenden. Um das Senden von Benachrichtigungen bei einem Statuswechsel bei allen diesen Hosts zu unterbinden, setzen Sie im Template einfach die Direktive notifications_enabled auf »0«. Wichtig ist beim Anlegen von Templates, dass die Direktive register 0 gesetzt ist. Damit wird ein Template als ein solches gekennzeichnet und von Nagios nicht als echter Host betrachtet. Ohne diese Kennzeichnung würde Nagios dieses Template in die Überwachung einbeziehen, was aus verständlichen Gründen wenig sinnvoll ist. Betrachten Sie dieses Template als eine abstrakte Klasse, um in der Sprachweise der objektorientierten Programmierung zu bleiben. Sinn und Unsinn von Templates Bei der Überwachung einzelner Systeme erschließt sich die Mächtigkeit und der Vorteil von Templates bei der Nagios-Konfiguration häufig nicht, denn eine Konfiguration für ein oder zwei Systeme ist schnell auch ohne Templates erstellt. Bei der Verwaltung großer Infrastrukturen ist es allerdings ungeheuer hilfreich, gleiche Eigenschaften von Objekten zusammenfassen zu können. Globale Änderungen, die alle Hosts betreffen, müssen dann nur zentral am Template durchgeführt werden und nicht für jeden Host einzeln. Dasselbe gilt für Services und andere Objekte in Nagios: Für kleine Anwendungen sind Templates häufig überflüssig. Sobald Objekte in großer Zahl vorhanden sind und über ausreichend viele identische Eigenschaften verfügen, sind Templates eine große Hilfe.
Abbildung 5.16 zeigt das Template- und Vererbungsprinzip von Nagios. Das Template WWW legt globale Daten für einen bestimmten Servertyp fest, in diesem Beispiel für einen Webserver. Bei der Verwendung von Templates ist es sinnvoll, Systeme mit gleichen Eigenschaften zu gruppieren, also z. B. ein Template für Webserver, ein anderes für Datenbankserver, ein weiteres für Application-Server usw. Das in Abbildung 5.16 gezeigte Template legt alle den zu überwachenden Webservern gemeinsame Attribute fest, so dass die Webserver lediglich das zu verwendende Template und ihre individuellen Attribute besitzen.
use www host_name hardy.rodewig.de alias hardy address 192.168.100.100 Abbildung 5.16
use www host_name hardy2.rodewig.de alias hardy2 address 192.168.100.101
Vererbung in Nagios
Neben der Möglichkeit der Vererbung bietet Nagios noch die Möglichkeit, Hosts zu Hostgroups und Services zu Servicegroups zusammenzufassen. Der Sinn dahinter liegt sowohl in der Vereinfachung der Konfiguration als auch darin, die Übersichtlichkeit der Überwachung zu erhöhen und zusammenhängende Dienste und Hosts in der Statusübersicht als solche kennzeichnen zu können. Dies ist insbesondere bei der Überwachung größerer Infrastrukturen von Bedeutung. Eine Hostgroup, bestehend aus den zwei Webservern hardy und hardy2, wird wie folgt definiert: define hostgroup { hostgroup_name alias members }
webserver Web-Server hardy, hardy2
Das Anlegen von Hosts in der Konfiguration von Nagios ist nur die halbe Miete. Damit Nagios Hosts überprüfen kann, müssen Services definiert und den zu überprüfenden Hosts zugewiesen werden. Die Verwendung von Templates ist dabei auch bei einer kleinen zu überwachenden Infrastruktur überaus sinnvoll. Nagios bringt ein Standard-Template für Services mit, den generic-service: define service{ name active_checks_enabled passive_checks_enabled parallelize_check
In der Regel, insbesondere bei der Überwachung eines einzelnen Servers, wird man für die verschiedenen Services dieselben Attribute verwenden. Je nachdem, wie unterschiedlich sich die zu überwachenden Dienste verhalten, können einzelne Attribute aus dem Template in die konkreten Service-Objekte verlagert werden. Direktiven zur Benachrichtigung beispielsweise sind bei einem nicht in einem Rechenzentrum stehenden und mit 7×24-Stunden-Support versorgten System eher von geringerer Bedeutung und werden in einem solchen Fall mit hoher Wahrscheinlichkeit für alle Services gleich sein können. Für die Definition von Eskalationsketten kennt Nagios zwei wichtige Objekte: Timeperiods und Contacts. Timeperiods sind Angaben über Zeiträume, innerhalb derer Nagios Benachrichtigungen rausschickt. Haben Sie einen 7×24-Stunden-Support für Ihren Server, können Sie die Standard-Timeperiod verwenden. Wenn der Support ohnehin nur wochentags von 8–16 Uhr erreichbar ist, sollten Sie die Timeperiod entsprechend anpassen, um zu verhindern, dass die Inbox des Supports (oder Ihre Inbox) in der Zeit zwischen 16 und 8 Uhr und am Wochenende von Nagios mit Mails zugepflastert wird. Eine entsprechende Definition dieser Timeperiod sieht wie folgt aus: define timeperiod{ timeperiod_name alias Monday Tuesday
support_zeiten Arbeitszeit 0800-1600 0800-1600
315
5.1
5
Optimierung und Monitoring
Wednesday Thursday Friday
0800-1600 0800-1600 0800-1600
}
Einen zu benachrichtigenden Kontakt können Sie über das Objekt contact erzeugen: define contact{ contact_name alias service_notification_period host_notification_period service_notification_options host_notification_options service_notification_commands host_notification_commands email }
support Server-Support support_zeiten support_zeiten w,u,c,r d,r notify-by-email host-notify-by-email [email protected]
In der Definition des Kontakts verwenden Sie die passende Timeperiod. Mit der Direktive service_notification_options können Sie festlegen, bei welchen Status eines Services dieser Kontakt benachrichtigt werden soll. Mögliche Werte sind die Kürzel der möglichen Status, wobei r für recovery steht, eine Benachrichtigung also dann erzeugt wird, wenn ein Host oder Service sich wieder erholt hat und in den Status OK zurückwechselt. Den Fall, dass ein Host ganz ausfällt, repräsentiert das Kürzel d (down). Für die Überwachung eines Services stehen verschiedene Direktiven zur Verfügung. Einige sind verpflichtend, andere optional. Die folgende Tabelle zeigt alle möglichen Direktiven. Optionale Direktiven sind dabei mit einem Stern gekennzeichnet. Direktive
Bedeutung
name
Der Name eines Services, wenn dieser nur als Template vorhanden ist. Andere Services können diesen Service über diesen Namen einbinden und seine Attribute erben.
host_name
Name des oder der Hosts, auf dem oder denen dieser Service läuft.
hostgroup_name*
Zusätzlich oder alternativ zur vorstehenden Direktive host_ name kann mit dieser Direktive eine ganze Hostgruppe angegeben werden.
Tabelle 5.1 Direktiven zur Überwachung eines Services (*: optionale Direktiven)
316
Monitoring
Direktive
Bedeutung
service_description
Eine Beschreibung des Dienstes. Die hier festgelegte Bezeichnung wird in der Nagios-Oberfläche angezeigt.
display_name*
Falls Sie auf der Nagios-Oberfläche einen anderen Namen als die service_description angezeigt bekommen möchten, können Sie diese Direktive dazu verwenden.
servicegroups*
Gehört der Service zu einer Servicegroup, kann diese hiermit festgelegt werden.
is_volatile*
Kennzeichnet einen volatilen Service. Bei volatilen Services wird bei jeder Prüfung, die einen Hard State zurückgibt, eine Benachrichtigung erzeugt und der entsprechende Event Handler aufgerufen. Details dazu enthält der folgende Abschnitt.
check_command
Der Name des Befehls, der zur Überprüfung verwendet wird.
initial_state*
Ausgangsstatus des Services. Nicht jeder Service muss sich zu Beginn der Überprüfung durch Nagios im Status OK befinden. Mögliche Werte sind die Kürzel der vier Status O, W, C, U (OK, WARNING, CRITICAL, UNKOWN).
max_check_attempts
Anzahl der Überprüfungen, die Nagios durchführt, bevor der Service als nicht OK festgelegt wird.
check_interval
Anzahl der Minuten zwischen zwei Überprüfungen, während der Service im Status OK ist. Über die Direktive interval_ length in der zentralen Nagios-Konfiguration kann die Einheit des Intervalls geändert werden. Der Standardwert ist 60 und steht für 60 Sekunden. Ein Wert von 1 bei check_interval bedeutet also, dass zwischen zwei Überprüfungen 60 Sekunden liegen.
retry_interval
Nach dem Wechsel von OK in einen anderen Status gilt nicht mehr das check_interval, sondern das retry_interval. Die Bedeutung ist allerdings dieselbe und legt den Abstand zwischen zwei Überprüfungen des Services fest.
active_checks_ enabled*
Legt fest, ob aktive Checks für diesen Service erlaubt sind.
passive_checks_ enabled*
Legt fest, ob passive Checks für diesen Service erlaubt sind.
check_period
Diese Direktive legt den Namen der Timeperiod fest, innerhalb derer der Service geprüft wird. Näheres dazu beschreibt der folgende Abschnitt.
obsess_over_service*
Legt fest, ob der mit der Direktive ocsp_command in der zentralen Nagios-Konfiguration definierte Befehl nach jedem Check ausgeführt werden soll oder nicht. Zum Thema Automatismus lesen Sie bitte das nächste Hinweisfeld weiter unten.
Tabelle 5.1 Direktiven zur Überwachung eines Services (*: optionale Direktiven) (Forts.)
317
5.1
5
Optimierung und Monitoring
Direktive
Bedeutung
check_freshness*
Gibt an, ob Nagios so genannte Freshness-Prüfungen für diesen Service durchführen soll. Freshness-Prüfungen stellen sicher, dass Nagios eine Überprüfung regelmäßig durchführt und die Ergebnisse somit immer auf einem aktuellen Stand, also »frisch«, sind.
freshness_threshold*
Legt das Intervall für die Freshness-Prüfungen fest.
event_handler*
Befehl, der als Event Handler für diesen Dienst ausgeführt wird.
event_handler_ enabled*
Gibt an, ob der event_handler aufgerufen wird oder nicht.
flap_detection_ enabled*
Aktiviert oder deaktiviert die Flap-Erkennung für diesen Dienst. Aktivierte Flap-Erkennung ist sinnvoll bei Diensten, die ihren Status häufig ändern, und verhindert, dass jedes Mal Benachrichtigungen erzeugt und Event Handler aufgerufen werden.
low_flap_threshold*
Legt die untere Grenze für die Flap-Erkennung fest.
high_flap_threshold*
Legt die obere Grenze für die Flap-Erkennung fest.
process_perf_data*
Aktiviert die Aufzeichnung von Daten über die Ausführung von Checks und Plugins. Damit können Sie z.B. deren Ausführungszeit messen.
retain_status_ information*
Legt fest, ob Statusinformationen über einen Programmneustart von Nagios erhalten bleiben sollen. Dieses Attribut ist nur wirksam, wenn in der zentralen Konfigurationsdatei die Direktive retain_state_information=1 gesetzt ist.
retain_nonstatus_ information*
Analog zum vorstehenden Attribut legt dieses Attribut fest, ob nicht statusbezogene Informationen zum Service einen Neustart von Nagios überdauern sollen.
notification_interval Definiert das Intervall, in dem Benachrichtigungen erzeugt
werden, solange sich der Dienst nicht im Status OK befindet. notification_period
Legt die Timeperiod fest, innerhalb derer Benachrichtigungen gesendet werden.
notification_options* Mit dieser Direktive können Sie angeben, zu welchen Status
Benachrichtigungen gesendet werden sollen. notifications_ enabled*
Aktiviert oder deaktiviert das Senden von Benachrichtigungen.
contacts
Liste von Kontakten, die im Falle von Statuswechseln benachrichtigt werden.
contact_groups
Analog zur vorstehenden Direktive übernimmt als Argument eine oder mehrere Contactgroups.
Tabelle 5.1 Direktiven zur Überwachung eines Services (*: optionale Direktiven) (Forts.)
318
Monitoring
Direktive
Bedeutung
stalking_options*
Erlaubt die Aktivierung erweiterter Loggings durch Nagios. Dieses Attribut ist nur dann sinnvoll, wenn Sie eine eingehende Logfileanalyse betreiben möchten, und erzeugt wesentlich mehr Logdaten als im normalen Betriebsmodus.
use*
Bindet ein Template ein.
required*
Ist der Wert 0, stellt die Service-Definition lediglich ein Template dar und wird von Nagios nicht als eigenständiger Dienst erkannt. Andere Services können dieses Template über die use-Direktive einbinden.
Tabelle 5.1 Direktiven zur Überwachung eines Services (*: optionale Direktiven) (Forts.)
Bei der Konfiguration von Nagios werden Sie unweigerlich darauf stoßen, dass Nagios zwischen verschiedenen Status von Hosts und Services unterscheidet. Damit sind nicht die vier Zustände gemeint, die Nagios in der Weboberfläche ausgibt (OK, CRITICAL, WARNING und UNKNOWN), sondern eine interne Zuordnung von Zuständen aufgrund verschiedener ermittelter Ereignisse und in Abhängigkeit von vorherigen Status. Sobald ein Objekt (Host oder Service) den Status OK verlässt, befindet es sich im Soft State, allerdings nur so lange, wie Nagios diesen Zustand nicht erneut überprüft hat. Kann Nagios den von OK abweichenden Status durch eine erneute Überprüfung bestätigen, liegt ein Hard State vor. Wechselt das betreffende Objekt vor der erneuten Überprüfung aus dem Soft State zurück in den Status OK, ist dies für Nagios ein Soft Recovery. Analog dazu liegt ein Hard Recovery vor, wenn ein Objekt von einem Hard State zurück zu OK wechselt. Wechselt ein Objekt von einem Hard State in einen anderen, nennt sich der Zustand Hard State Change. In beiden Fällen, dem Eintreten eines Soft State oder eines Hard State, erzeugt Nagios ein Event (Soft State Event oder Hard State Event). Für jedes Event kann ein eigener Event Handler definiert werden. Das kann ein Programm sein, das beim Eintreten eines Events ausgeführt wird. Der Ausfall eines überwachten Prozesses kann z. B. einen Event Handler aufrufen, der den Prozess neu startet. So sind beliebige Reaktionen auf Events möglich. Neben Events erzeugt Nagios beim Wechsel von Status auch Benachrichtungen, die – in Abhängigkeit von der Konfiguration – den oder die zuständigen Administratoren über verschiedene Wege darüber informieren können, dass ein Problem vorliegt. Wichtig für das Verständnis der Arbeitsweise von Nagios ist in diesem Zusammenhang, dass Nagios immer nur dann eine Benachrichtigung erzeugt und den entsprechenden Event Handler aufruft, wenn sich ein Wechsel von einem Status in einen anderen Status ergeben hat. Beim Wechsel in einen Soft State loggt Nagios
319
5.1
5
Optimierung und Monitoring
diesen Vorfall, erzeugt aber keine Benachrichtigung. Beim Wechsel in einen Hard State wird dies entsprechend auf der Nagios-Oberfläche angezeigt, der Event Handler aufgerufen und eine Benachrichtigung versendet (sofern konfiguriert). Dies geschieht aber nur einmal, nämlich nach dem Wechsel in den Hard State. Ergibt eine erneute Überprüfung, dass sich Host oder Service immer noch in diesem Hard State befinden, erfolgt keine weitere Reaktion, erst wenn sich der Hard State ändert. Bei volatilen Services erzeugt Nagios bei jeder Überprüfung, die einen Hard State ergibt, eine Benachrichtigung und ruft den Event Handler auf. Der Fluch des Automatismus Das Verwenden von Event Handlern erscheint auf den ersten Blick praktisch und ermöglicht theoretisch das sich selbst heilende System. In der Praxis sieht die Situation aber leider anders aus. Sicher kann ein Event Handler für den Zustand »Festplatte voll« darin bestehen, durch Löschen überflüssiger Dateien Platz auf der Platte zu schaffen. Aber wie soll ein dummes Programm erkennen können, welche Daten überflüssig sind, ob die Platte wirklich wegen zu vieler Daten voll ist oder ob nicht viel eher ein Hardwaredefekt vorliegt, der den freien Plattenplatz rapide schrumpfen lässt? Ein gut gemeinter, dafür aber schlecht umgesetzter Event Handler kann mehr Schaden erzeugen als das eigentliche Event. Seien Sie deshalb vorsichtig und umsichtig beim Einsatz von Event Handlern.
Netzwerkchecks Die Standardkonfiguration von Nagios bringt eine vorgefertigte Konfiguration für die Prüfung des lokalen Hosts, also des Nagios-Servers, mit. Das ist natürlich wenig nützlich für die Überprüfung eines Servers im Internet. Wie weiter oben beschrieben, ist es für die kontinuierliche Überwachung eines Servers sinnvoll, den NagiosServer nicht auf demselben System zu betreiben. Fällt der Server komplett aus, kann auch Nagios nicht mehr arbeiten. Benachrichtigungen und Überwachung für die spätere Analyse des Ausfalls sind damit auch nicht mehr möglich. Daher sollten Sie Nagios stets auf einem anderen System installieren und dieses System im Idealfall so platzieren, dass es die Sicht eines Benutzers einnimmt, also auf demselben Weg auf den zu überwachenden Server zugreift wie Benutzer. Das kann ein Rechner bei Ihnen unter dem Schreibtisch sein, der über die DSL-Leitung auf den zu überwachenden Server zugreift, oder ein V-Server im Internet. Im letzteren Fall sollten Sie einen anderen Provider wählen als den, bei dem der zu überwachende Server gehostet ist. Damit umgehen Sie den Fall, dass Probleme beim Provider zum Ausfall Ihres Servers führen, Nagios dies aber nicht erkennt, weil der Zugriff auf den zu überwachenden Server über interne Verbindungen beim Provider führt und keine Aussage über die Erreichbarkeit aus dem Internet möglich ist. Zur Überwachung eines entfernten Systems müssen Sie im ersten Schritt eine Host-Definition erstellen. Darin legen Sie das zu verwendende Template, den Host-Namen, einen Alias und die IP-Adresse des zu überprüfenden Systems an:
320
Monitoring
define host{ use host_name alias address }
generic-host hardy hardy 192.168.0.20
Im zweiten Schritt definieren Sie die Services, die Nagios von außen auf diesem System überwachen soll, also die über das Netzwerk erreichbaren Dienste. In diesem Beispiel sind das der FTP-Server, der Apache-Webserver und der OpenSSHServer. Zusätzlich ist es hilfreich, die Erreichbarkeit per ICMP zu überwachen, um auch beim Ausfall aller Dienste feststellen zu können, ob der Host netzwerktechnisch noch erreichbar ist. Damit lässt sich bei einem Ausfall eher eingrenzen, ob ein Problem des Hosts oder der Internetanbindung besteht. Die Service-Definitionen dafür sehen wie folgt aus: define service{ # Apache-Webserver use generic-service host_name hardy service_description HTTP check_command check_http } define service { # OpenSSH-Server host_name hardy service_description SSH check_command check_ssh use generic-service } define service { # FTP-Server host_name hardy service_description FTP check_command check_ftp use generic-service } define service { # ICMP host_name hardy service_description PING check_command \ check_ping!100.0,20 %!500.0,60 % use generic-service }
321
5.1
5
Optimierung und Monitoring
Die Zahlenwerte hinter den Überwachungsbefehlen geben die Schwellwerte an, die Nagios für das Festlegen der Status verwendet. Der erste Wert legt die Eintrittsbedingung für den Status WARNING fest, der zweite die des Status CRITICAL. Auf Betriebssystemebene übergibt Nagios dem jeweiligen Plugin den ersten Wert mit dem Kommandozeilenparamenter -w, den zweiten mit dem Parameter -c. Dies ist wichtig für die Entwicklung eigener Plugins. Gruppierung von Objekten Bei der Konfiguration von Nagios gibt es verschiedene Arten, die Objekte zu gruppieren und auf verschiedene Konfigurationsdateien aufzuteilen. Für kleine Infrastrukturen ist es am übersichtlichsten, alle Objekte, die zu einem Host gehören, in eine einzige Konfigurationsdatei zu speichern. Wenn Sie nur eine überschaubare Anzahl von Systemen überwachen möchten, legen Sie für jedes System eine eigene Konfigurationsdatei an und legen alle systemspezifischen Objekte darin ab, also insbesondere die Host- und ServiceDefinitionen. Sobald die zu überwachende Infrastruktur größere Ausmaße annimmt und die Anzahl der zu überwachenden Systeme unüberschaubar wird, führt dieser Ansatz auch zu einer unüberschaubaren Anzahl von Konfigurationsdateien. Dann ist es ratsam, die Objekte nach ihrem Typ zu sortieren, so dass es für alle Hosts eine eigene Konfigurationsdatei gibt, für alle Services eine weitere eigene etc. Wo Sie die Grenze ziehen, ist Auslegungssache. Für den Anfang ist der erste Ansatz übersichtlicher und intuitiver.
Speichern Sie die Objektdefinitionen in einer neuen Konfigurationsdatei im Verzeichnis /etc/nagios2/conf.d (z. B. .cfg), und starten Sie Nagios anschließend neu. # sudo /etc/init.d/nagios2 restart
Nach dem Neustart kennt Nagios den neuen Host und wird die konfigurierten Services in die Überwachung mit einbeziehen. Über die Nagios-Oberfläche können Sie dann den Status des Hosts einsehen (Abbildung 5.17).
Abbildung 5.17
Der neue Host in der Überwachung
Um festzustellen, ob Nagios auch wirklich den korrekten Systemzustand anzeigt, machen Sie die Probe aufs Exempel: Stoppen Sie den FTP-Server auf dem überwachten System:
322
Monitoring
# sudo /etc/init.d/proftpd stop
Nach der nächsten zyklischen Überprüfung wird Nagios dies anzeigen und – sofern konfiguriert – eine Benachrichtigung verschicken.
Abbildung 5.18
Der FTP-Dienst im Zustand CRITICAL
Um die Erreichbarkeit der extern erreichbaren Dienste zu überwachen, ist diese Konfiguration bereits ausreichend. Allerdings erlaubt sie lediglich das Erkennen von Fehlern, wenn diese eintreten. Ein vorausschauendes Monitoring wichtiger Systemparameter wie Speicherverbrauch, CPU-Last und Festplattenbelegung ist damit allerdings noch nicht möglich. Gerade diese Parameter erlauben aber bei einer sorgfältig konfigurierten Überwachung ein rechtzeitiges Eingreifen, so dass sich Fehler gar nicht erst im Ausfall von Diensten oder des Systems manifestieren müssen. Damit diese Parameter überwacht werden können, muss auf dem zu überwachenden System NRPE oder NSCA installiert und konfiguriert sein, so dass Nagios Befehle direkt auf dem System abrufen kann. Alternativ können Sie MRTG im Parallelbetrieb verwenden und die Parameter per SNMP auslesen. Das parallele Pflegen zweier Überwachungssysteme ist allerdings unnötiger Aufwand, da Nagios alles mitbringt, was für das Abfragen lokaler Parameter notwendig ist. NRPE NRPE, der Nagios Remote Plugin Executor, erlaubt das Ausführen von NagiosPlugins auf entfernten Systemen. Dazu läuft auf diesen Systemen ein NRPEDienst, der Anfragen eines Nagios-Servers entgegennimmt, die entsprechenden Prüfungen ausführt und das Ergebnis an den Nagios-Server zurücksendet. Damit Sie NRPE verwenden können, müssen Sie auf dem zu überwachenden System die folgenden Pakete installieren: # sudo apt-get install nagios-nrpe-server nagios-plugins nagiosplugins-basic
bzw. # emerge nagios-nrpe
323
5.1
5
Optimierung und Monitoring
Der NRPE-Dienst wird über die Datei /etc/nagios/nrpe.cfg konfiguriert – sowohl bei Ubuntu als auch unter Gentoo. Die Standardkonfiguration startet den Dienst auf TCP-Port 5666 und legt als Benutzerumgebung für den NRPE-Dienst den Benutzer und die Gruppe nagios fest. Die folgenden Direktiven in der Konfigurationsdatei sollten Sie in jedem Fall beachten. allowed_hosts=192.168.0.22
Mit dieser Direktive legen Sie die IP-Adresse fest, von der aus auf den NRPEDienst zugegriffen werden darf. Dies ist zwar ein schwacher Schutz vor Angriffen, schränkt aber die Erreichbarkeit des Dienstes und damit die Möglichkeit für einen Angreifer, den Dienst aufzufinden, stark ein. An der Einstellung der folgenden Direktive sollten Sie niemals etwas ändern: dont_blame_nrpe=0
Wenn der Wert dieser Direktive 1 ist, nimmt der NRPE-Dienst beliebige Befehle über das Netzwerk entgegen und führt diese auf der lokalen Maschine aus. Eine bessere Angriffsmöglichkeit gibt es nicht. Zwar werden die Befehle mit den Rechten des Benutzers nagios ausgeführt, aber auch damit kann ein Angreifer schon erheblichen Schaden anrichten. Für die Einrichtung der Nagios-Überwachung ist ein erhöhter Loglevel hilfreich, weswegen Sie über die Direktive … debug=1
… den NRPE-Dienst anweisen, seine Logdaten an den lokalen Syslog-Daemon zu senden. Die Befehle, die NRPE von Nagios entgegennimmt und ausführt, müssen – sofern die Direktive dont_blame_nrpe nicht gesetzt ist – in der Konfigurationsdatei definiert sein. NRPE bringt eine kleine Anzahl von Beispielen mit: command[check_users]=\ /usr/lib/nagios/plugins/check_users -w 5 -c 10 command[check_load]=\ /usr/lib/nagios/plugins/check_load -w 15,10,5 -c 30,25,20 command[check_hda1]=\ /usr/lib/nagios/plugins/check_disk -w 20 -c 10 -p /dev/hda1 command[check_zombie_procs]=\ /usr/lib/nagios/plugins/check_procs -w 5 -c 10 -s Z command[check_total_procs]=\ /usr/lib/nagios/plugins/check_procs -w 150 -c 200
Bei diesen Beispielen sind die Schwellwerte fest in der Konfigurationsdatei von NRPE abgelegt, erkennbar an den Zahlenwerten bei den Befehlen. NRPE ist unter
324
Monitoring
Ubuntu standardmäßig mit der Unterstützung variabler Argumente übersetzt, was das Senden individueller Befehle vom Nagios-Server voraussetzt. Da dafür dont_ blame_nrpe aktiviert sein muss, ist von dieser Betriebsart dringend abzuraten. Sie können die Funktionstüchtigkeit von NRPE testen, indem Sie von dem Nagios-Server, der in der nrpe.cfg als autorisierter Host eingetragen ist, manuell Überprüfungen per NRPE anstoßen. Verwenden Sie dazu das Plugin check_nrpe mit einem auf dem zu überprüfenden Host in der NRPE-Konfiguration eingetragenen Befehl. Unter Ubuntu befinden sich die Nagios-Plugins wie das NRPEPlugin im Verzeichnis /usr/lib/nagios/plugins, unter Gentoo im Verzeichnis /usr/ nagios/libexec. Der Aufruf des Plugins mit dem Parameter -h gibt einen Hilfetext aus, der die korrekte Verwendung erklärt: # /usr/lib/nagios/plugins/check_nrpe -h NRPE Plugin for Nagios Copyright (c) 1999-2007 Ethan Galstad ([email protected]) Version: 2.8.1 Last Modified: 05-10-2007 License: GPL v2 with exemptions (-l for more info) SSL/ TLS Available: Anonymous DH Mode, OpenSSL 0.9.6 or higher required Usage: check_nrpe -H [-n] [-u] [-p <port>] [-t ] [-c ] [-a <arglist...>] [...] Note: This plugin requires that you have the NRPE daemon running on the remote host. You must also have configured the daemon to associate a specific plugin command with the [command] option you are specifying here. Upon receipt of the [command] argument, the NRPE daemon will run the appropriate plugin command and send the plugin output and return code back to *this* plugin. This allows you to execute plugins on remote hosts and 'fake' the results to make Nagios think the plugin is being run locally.
Neben der Erläuterung der korrekten Syntax ist der letzte Absatz des Hilfetextes interessant, da dort die Funktionsweise des Plugins beschrieben ist. Hilfe zu den Nagios-Plugins Der Kommandozeilenparameter -h ruft bei allen Nagios-Plugins einen Hilfetext auf. Da alle Nagios-Plugins ausführbare Programme sind, können Sie auf der Kommandozeile alle Plugins ausführen, was bei der Implementierung neuer Überprüfungen oder der Entwicklung eigener Plugins enorm hilfreich ist, da Sie auf der Kommandozeile umgehend eine Rückmeldung erhalten. Insbesondere bei Plugins, die individuelle Schwellwerte als Parameter erwarten, ist die Hilfedatei eine gute Referenz.
325
5.1
5
Optimierung und Monitoring
Auf dem zu überwachenden System können Sie im Syslog die Logausgaben des NRPE-Servers kontrollieren: # sudo tail -f /var/log/syslog Sep 6 03:13:14 hardy nrpe[9560]: Starting up daemon Sep 6 03:13:14 hardy nrpe[9560]: Listening for connections on port 5666 Sep 6 03:13:14 hardy nrpe[9560]: Allowing connections from: 192.168.0.22
Führen Sie auf dem Nagios-Server das Plugin nrpe_check aus, und übergeben Sie einen Befehl, der nicht in der nrpe.cfg auf dem Zielsystem konfiguriert ist: # /usr/lib/nagios/plugins/check_nrpe -H 192.168.0.20 -c foobar NRPE: Command 'foobar' not defined
Im Syslog des NRPE-Servers finden Sie die Angabe, dass der empfangene Befehl nicht bekannt ist und die Anfrage daher verworfen wurde: Sep 6 03:14:22 hardy nrpe[9568]: port 28349 Sep 6 03:14:22 hardy nrpe[9568]: Sep 6 03:14:22 hardy nrpe[9568]: Sep 6 03:14:22 hardy nrpe[9568]: 'foobar' to be run... Sep 6 03:14:22 hardy nrpe[9568]: Sep 6 03:14:22 hardy nrpe[9568]: Command 'foobar' not defined Sep 6 03:14:22 hardy nrpe[9568]: closed.
Connection from 192.168.0.22 Host address is in allowed_hosts Handling the connection... Host is asking for command NRPE: Command 'foobar' not defined Return Code: 2, Output: NRPE: Connection from 192.168.0.22
Anders sieht es aus, wenn Sie einen gültigen Befehl ausführen: # /usr/lib/nagios/plugins/check_nrpe -H 192.168.0.20 -c check_total_procs PROCS OK: 68 processes
Das Plugin erhält vom NRPE-Server eine gültige und sinnvolle Antwort, und auf dem NRPE-Server gibt es einen entsprechenden Eintrag im Syslog: Sep 6 03:17:44 hardy nrpe[9649]: Connection from 192.168.0.22 port 34493 Sep 6 03:17:44 hardy nrpe[9649]: Host address is in allowed_hosts Sep 6 03:17:44 hardy nrpe[9649]: Handling the connection... Sep 6 03:17:44 hardy nrpe[9649]: Host is asking for command 'check_total_procs' to be run... Sep 6 03:17:44 hardy nrpe[9649]: Running command: /usr/lib/nagios/plugins/check_procs -w 150 -c 200
NRPE funktioniert augenscheinlich und kann jetzt für die Überwachung durch Nagios verwendet werden. Unter Ubuntu sind zwei verschiedene Befehle für check_nrpe konfiguriert, einmal für den Aufruf mit einem Argument (check_ nrpe_1arg) und einmal für den Aufruf mit mehreren Argumenten (check_nrpe). Die erste Version ist für Befehle bestimmt, die außer dem Host-Namen keine weiteren Argumente benötigen und bei denen die Konfiguration der Schwellwerte in der NRPE-Konfiguration abgelegt ist. Die zweite Version benötigt den unsicheren dont_blame_nrpe-Modus und ist daher für den Betrieb nicht zu empfehlen. Verwenden Sie immer check_nrpe_1arg, und konfigurieren Sie die Überwachungsbefehle fest in der nrpe.cfg auf den zu überwachenden Systemen. Um die unter Ubuntu bereits vorkonfigurierten Überwachungsbefehle von NRPE in die Überwachung aufzunehmen, erweitern Sie die Konfigurationsdatei des zu überwachenden Systems um die folgenden Objekte: define service { # Anzahl der aktiven Prozesse host_name hardy service_description Prozesse check_command check_nrpe_1arg!check_total_procs use generic-service } define service { # Load host_name hardy service_description Load check_command check_nrpe_1arg!check_load use generic-service } define service { # eingeloggte Benutzer host_name hardy service_description Benutzer check_command check_nrpe_1arg!check_users use generic-service } define service { # Zombie-Prozesse
327
5.1
5
Optimierung und Monitoring
host_name service_description check_command use } define service { # Root-Partition host_name service_description check_command use }
Das letzte Objekt müssen Sie an die in Ihrem System korrekte Root-Partition anpassen. Dazu reicht es allerdings nicht, den Aufruf auf dem Nagios-Server anzupassen – in der NRPE-Konfiguration auf dem Zielsystem muss die entsprechende Zeile ebenfalls angepasst werden: command[check_sda2]=/usr/lib/nagios/plugins/check_disk -w 20 -c 10 -p /dev/sda2
Die Werte bedeuten, dass bei 20 % freiem Speicherplatz Nagios den Status WARNING für die Partition anzeigt, ab 10 % den Status CRITICAL. Nach der Änderung der Konfigurationsdateien müssen Sie den Nagios-Server und den NRPE-Server auf dem jeweiligen System neu starten: # sudo /etc/init.d/nagios2 restart # sudo /etc/init.d/nagios-nrpe-server restart
Nach dem Ausführen aller Kommandos zeigt Nagios alle gewünschten Informationen für den Host an.
Abbildung 5.19
328
Status-Abfragen per NRPE
Monitoring
Sichere Kommunikation NRPE ist unter Ubuntu und Gentoo bereits mit SSL-Unterstützung kompiliert (unter Gentoo allerdings nur dann, wenn das SSL-USE-Flag gesetzt ist). Damit findet die Kommunikation zwischen Nagios-Server und dem NRPE-Dienst verschlüsselt statt. Die SSLUnterstützung geht allerdings nicht so weit, dass Nagios oder der NRPE-Dienst gegenseitig Zertifikate verwenden oder überprüfen. Damit ist eine Authentifizierung über SSL nicht möglich. Bedenken Sie diese Einschränkung bei der Einschätzung der Sicherheit.
NSCA Bei NRPE läuft die Kommunikation vom Nagios-Server zum überwachten Host. Diese Richtung ist ideal, wenn der Nagios-Server in einem internen Netzwerk steht und einen Server im Internet überwacht. Alle Zugriffe finden aus dem internen Netz ins Internet statt, so dass keine Löcher in die Firewall gebohrt werden müssen. Diese Kommunikationsrichtung ist aber nicht immer angebracht. In größeren Infrastrukturen kann es sein, dass sich der Nagios-Server in einem DMZ-Bereich befindet, neben den dort befindlichen Hosts aber auch Systeme im internen Netzwerk überwachen muss. In diesem Fall müsste ein Zugriff des Nagios-Servers durch die Firewall ins interne Netz geschaffen werden, was ein potentielles Sicherheitsrisiko darstellt. Aus diesem Grund ist in diesem Fall NRPE nicht das Mittel der Wahl, sondern NSCA, der Nagios Service Check Acceptor. NSCA geht den umgekehrten Weg und sendet Daten vom überwachten System zum Nagios-Server. Dazu muss auf dem Nagios-Server die Unterstützung externer Befehle aktiviert sein. Diese Unterstützung erlaubt das Absetzen von Befehlen über die Nagios-Oberfläche, z. B. um eine Downtime zu planen oder um die Ausführung eines Checks zu einem bestimmten Zeitpunkt zu veranlassen. Aus Sicherheitsgründen ist die Unterstützung externer Befehle unter Ubuntu deaktiviert. Um sie zu aktivieren, muss zunächst in der zentralen Konfigurationsdatei von Nagios die Direktive check_external_commands den Wert 1 zugewiesen bekommen. Damit wird Nagios angewiesen, in der Datei /var/lib/nagios2/rw/nagios.cmd nach Befehlen zu suchen. Diese Befehle können über die Weboberfläche in diese Datei eingetragen werden oder vom NSCA-Dienst, der auf dem Nagios-Server laufen muss, wenn NSCA zum Einsatz kommt. Aus unerklärlichen Gründen sind die Dateisystem-Berechtigungen auf die Datei nagios.cmd unter Ubuntu nach der Installation so gesetzt, dass das Aktivieren der externen Befehle in der Konfigurationsdatei allein nicht dazu führt, dass Nagios damit umgehen kann. Sie müssen darüber hinaus noch die Dateisystem-Berechtigungen der Datei korrigieren:
Unter Ubuntu installieren Sie NSCA über das gleichnamige Paket: # sudo apt-get install nsca
Das Paket enthält den NSCA-Server, der auf dem Nagios-Server laufen muss und die Verbindungen des NSCA-Clients auf dem zu überwachenden Server entgegennimmt. Auf beiden Systemen muss dieses Paket installiert werden, der Server muss allerdings nur auf dem Nagios-Server laufen. Daher sollten Sie auf dem zu überwachenden System nach der Installation den NSCA-Server wieder anhalten und die Init-Skripte für den automatischen Start entfernen: # sudo /etc/init.d/nsca stop # sudo update-rc.d -f nsca remove Removing any system startup links for /etc/init.d/nsca ... /etc/rc2.d/K16nsca /etc/rc3.d/K16nsca /etc/rc4.d/K16nsca /etc/rc5.d/K16nsca
Die Konfigurationsdatei von NSCA liegt nach der Installation direkt im etc-Verzeichnis (/etc/nsca.cfg). Das ist arg unglücklich, da die thematisch verwandten Konfigurationsdateien im Verzeichnis /etc/nagios liegen. Der Übersichtlichkeit halber sollten Sie daher die Datei in dieses Verzeichnis verschieben: # sudo mv /etc/nsca.cfg /etc/nagios/
Damit der NSCA-Dienst die Datei auch findet, müssen Sie anschließend das Startskript des Dienstes entsprechend anpassen. Ändern Sie dazu in der Datei /etc/init.d/nsca den Wert der Variablen CONF in den neuen Ort der Konfigurationsdatei: CONF=/etc/nagios/nsca.cfg
Anschließend starten Sie den Service neu … # sudo /etc/init.d/nsca restart
… und prüfen das Ergebnis: # ps ax|grep nsca|grep -v grep 9191 ? Ss 0:00 /usr/sbin/nsca --daemon -c /etc/nagios/nsca.cfg
330
Monitoring
Voilà, der Dienst verwendet die verschobene Konfigurationsdatei. Bei Gentoo liegen die Konfigurationsdateien von NSCA bereits im »richtigen« Verzeichnis (/etc/ nagios). Unter Gentoo installieren Sie NSCA über das Paket nagios-nsca: # sudo emerge nagios-nsca
In der Konfigurationsdatei müssen Sie unter Ubuntu den Pfad zu der Datei anpassen, welche die externen Befehle enthält – standardmäßig ist dieser Pfad falsch: command_file=/var/lib/nagios2/rw/nagios.cmd
Sowohl unter Ubuntu als auch unter Gentoo sollten Sie bei der Verwendung von NSCA zwingend ein Passwort vergeben, mit dem der Client die an den Server geschickten Befehle verschlüsselt. Nur wenn Client und NSCA-Server dasselbe Passwort verwenden, erkennt der Server die Befehle als gültig an. Dies stellt ein zusätzliches Sicherheitsmerkmal dar und ist in jedem Fall eine gute Idee. Auf dem NSCA-Server – egal ob Gentoo oder Ubuntu – vergeben Sie daher in der Konfigurationsdatei des NSCA-Dienstes ein Passwort und wählen eine sichere Verschlüsselungsmethode aus. Der Standardwert (XOR) ist nicht sicher. In diesem Beispiel ist das Passwort 1234qwer (Achtung, auch nicht sicher!), und der verwendete Algorithmus ist AES256, ein als sicher geltender Industriestandard. password=1234qwer decryption_method=16
Nach der Änderung muss der NSCA-Server neu gestartet werden. Auf dem NSCA-Client, also dem von Nagios zu überwachenden System, erstellen Sie eine Datei /etc/nagios/send_nsca.cfg (unter Gentoo ist diese Datei bereits vorhanden) und schreiben die folgenden beiden Direktiven hinein: password=1234qwer encryption_method=16
Damit haben Sie das Gegenstück zu den Einstellungen auf dem NSCA-Server erstellt. Sie können die Funktionalität von NSCA über die Kommandozeile testen: # echo "hardy#Prozesse#0#OK" | send_nsca -H 192.168.0.22 -d '#' -c send_nsca.cfg 1 data packet(s) sent to host successfully.
Dieser manuelle Test zeigt auch das Format der NSCA-Meldungen: Hostname, Service, Returnwert und Status. Das Programm send_nsca sendet die Daten an den mit dem Parameter -H angegebenen Host, verwendet dabei das mit dem Parameter -d festgelegte Zeichen als Trennzeichen in dem Datensatz und über-
331
5.1
5
Optimierung und Monitoring
nimmt seine Einstellungen aus der mit dem Parameter -c spezifizierten Konfigurationsdatei. Auf dem Nagios- und NSCA-Server erscheint im Syslog eine entsprechende Meldung: Sep 7 18:20:11 hardy2 nsca[11239]: Connection from 192.168.0.20 port 11162 Sep 7 18:20:11 hardy2 nsca[11239]: Handling the connection... Sep 7 18:20:12 hardy2 nsca[11239]: SERVICE CHECK > Host Name: 'hardy', Service Description: 'Prozesse', Return Code: '0', Output: 'OK' Sep 7 18:20:12 hardy2 nsca[11239]: End of connection... Sep 7 18:20:12 hardy2 nagios2: EXTERNAL COMMAND: PROCESS_SERVICE_ CHECK_RESULT;hardy;Prozesse;0;OK
Um Services mit NSCA zu überwachen, müssen Sie diese auf dem Nagios-Server entsprechend konfigurieren und auf dem zu überwachenden System regelmäßig das Programm send_nsca ausführen, normalerweise per Cron-Job. Da das Verwenden externer Befehle in Nagios allerdings ein grundsätzliches Sicherheitsrisiko darstellt, sollte NSCA nur in begründeten Ausnahmefällen zum Einsatz kommen. Kennwörter, Dateien und die Sicherheit Die NSCA-Dateien, die das NSCA-Passwort enthalten, müssen gegen unbefugten Zugriff geschützt werden. Sie sollten daher unbedingt die Dateiberechtigungen der Dateien so restriktiv wie möglich festlegen.
Eigene Plugins Falls Ihnen die vorhandenen Plugins von Nagios nicht reichen, können Sie einfach eigene schreiben. Dabei gibt es nur einige wenige Rahmenbedingungen zu beachten: 왘
Das Plugin muss ein ausführbares Programm sein, wobei die verwendete Programmiersprache unerheblich ist. Vom Bash-Skript bis zum Java-Programm ist alles möglich, wenngleich nicht alles sinnvoll. Achten Sie darauf, dass das Plugin über korrekt gesetzte Dateirechte verfügt, so dass der Nagios- oder der NRPE-Daemon das Plugin ausführen können.
왘
Die Ausgabe des Programms darf nicht länger als 80 Zeichen sein, muss in einer Zeile ausgegeben werden und auf die Standardausgabe gehen (stdout).
왘
Das Plugin muss einen der vier möglichen Status zurückgeben: OK, WARNING, CRITICAL, UNKOWN.
332
Monitoring
Neben diesen drei verpflichtenden Bedingungen sollte ein selbstgeschriebenes Plugin über verschiedene Verbosity-Level verfügen und bei Bedarf einen Hilfetext ausgeben, analog zu den Hilfetexten der Standard-Plugins. Die einfachste Form eines Plugins ist ein selbstgewählter Befehl, der über NRPE ausgeführt wird. Eine nützliche Information ist z. B. die Ausgabe von uname, da sich darüber der Systemname und die Versionsnummer sowie andere Informationen über den aktiven Kernel eines Systems auslesen lassen. Um diese Informationen per NRPE von einem entfernten System auszulesen, definieren Sie auf diesem System in der Datei /etc/nagios/nrpe.cfg einen neuen Befehl und starten den NRPE-Dienst anschließend neu: command[check_uname]=/bin/uname -a
Unter dem Namen check_uname kann der Nagios-Server diesen Befehl ausführen. Auf dem Nagios-Server fügen Sie einen neuen Service zur Konfiguration des Hosts hinzu (den Neustart des Nagios-Dienstes nicht vergessen): define service { host_name service_description check_command use }
Das Ergebnis lässt sich nach der ersten Überprüfung dieses neuen Services durch Nagios auf der Nagios-Oberfläche betrachten (letzte Zeile in Abbildung 5.20). uname ist natürlich genau genommen kein standardkonformes Plugin, da es weder einen Status zurückliefert, noch eine Aussage über die Qualität eines Dienstes macht, es zeigt aber sehr schön, wie flexibel mit Nagios Informationen von einem System abgefragt werden können.
Abbildung 5.20 Die Ausgabe von »uname« von einem entfernten Rechner
333
5.1
5
Optimierung und Monitoring
5.1.4
Webserver-Statistiken
Neben der Überwachung betriebskritischer Parameter sind auf einem Webserver die Zugriffe auf die Website von besonderer Bedeutung, denn aus den Logdateien, die der Apache-Webserver über die Zugriffe der Benutzer anlegt, kann der Betreiber einer Website detaillierte Informationen über das Verhalten dieser Benutzer ermitteln. Die wichtigsten Basiskennzahlen im Online-Geschäft sind Page Impressions und Visits. Page Impressions geben die Anzahl der Seitenabrufe an, die Benutzer von einem Webserver angefordert haben. Eine Page Impression bezeichnet dabei den Abruf einer kompletten Webseite inklusive der darin enthaltenen Elemente. Darin unterscheidet sich die Kenngröße Page Impression von der reinen Abrufzahl, wie sie ein Webserver in der Logdatei vermerkt, denn der Webserver erzeugt pro abgerufenem Element einen Eintrag, so dass der Abruf einer Webseite, die verschiedene Grafiken und eingebundene weitere Webseiten enthält, zu entsprechend vielen Einträgen in der Logdatei des Servers führt. Der Begriff Page Impression wird insbesondere dann interessant, wenn Sie mit Ihrer Website durch Werbung Geld verdienen möchten und die Seitenzugriffe daher nach dem IVW-Verfahren3 ermitteln. In diesem Zusammenhang gibt es noch den Begriff Visit, der einen eindeutigen Besuch auf einer Website beschreibt. Über die Page Impressions und die Visits lassen sich Beliebtheit der Site, Beliebtheit von Unterseiten und das Besucherverhalten ermitteln. Das IVW-Verfahren ist ein kostenpflichtiger Dienst, der über proprietäre Systeme der IVW bereitgestellt wird. Grundlage des Verfahrens ist ein so genanntes Zählpixel, das in jede zu überwachende Webseite eingebaut wird. Dahinter verbirgt sich eine 1x1 Pixel große transparente Grafikdatei, die auf einem Webserver der IVW liegt. Über entsprechende Aufrufparameter bei der Verlinkung können die Aufrufe des Zählpixels jeder überwachten Website zugeordnet werden. In der Homepage des Nachrichtenmagazins SPIEGEL ist die Verlinkung des IVW-Pixels die folgende:
Bei der ARD sieht es ähnlich aus:
Der Aufruf einer Webseite, in der das Zählpixel verlinkt ist, führt somit also dazu, dass auf dem jeweiligen IVW-Host (*.ivwbox.de) das Pixel mit den übergebenen URL-Parametern abgerufen wird. Über IP-Adresse, Browserkennung und, je nach 3 http://www.ivw.de/
334
Monitoring
Konfiguration der Webseite, auch Cookies des Benutzers lassen sich mit diesen Daten Page Impressions und Visits ermitteln. Die Systeme, auf denen die Webserver mit den Zählpixeln laufen, sind so genannte IVW-Boxen, für IVW-Kunden abgeschlossene Systeme, die lediglich den Webdienst zur Verfügung stellen und über einen Socket den Logstrom des Webservers zur weiteren Auswertung an die IVW und den Betreiber der Website übermitteln. Die IVW ermittelt aus diesen Daten die auf der IVW-Website monatlich veröffentlichten Zugriffszahlen, der Systembetreiber kann mit den Daten eigene Auswertungen fahren. Das IVW-Verfahren lässt sich vom Benutzer leicht umgehen. Erweiterungen für gängige Browser, wie z. B. AdBlock Plus4 für Firefox, erlauben das Blockieren von Elementen, die der Browser dann gar nicht mehr abruft. Da die IVW-Auswertung allein durch die Implementierung der Überwachungsfunktion eine kostspielige Angelegenheit sein kann, lohnt sich das Verfahren in der Regel nur für große Anbieter. Eine Alternative dazu bietet der Google-Dienst Google Analytics. Dabei handelt es sich um einen kostenlosen Service, der über in Webseiten eingebetteten JavaScript-Code und den Gebrauch von Cookies sehr detaillierte Auswertungen über Zugriffe und das Benutzerverhalten auf einer Website darstellt. Die Besonderheit bei der Verwendung von Google Analytics ist, dass die erfassten Daten auf Servern von Google gesammelt und ausgewertet werden. Interessant sind in diesem Zusammenhang die Nutzungsbedingungen (Stand September 2008): »Die durch den Cookie erzeugten Informationen über Ihre Benutzung diese Website (einschließlich Ihrer IP-Adresse) wird an einen Server von Google in den USA übertragen und dort gespeichert. Google wird diese Informationen benutzen, um Ihre Nutzung der Website auszuwerten, um Reports über die Websiteaktivitäten für die Websitebetreiber zusammenzustellen und um weitere mit der Websitenutzung und der Internetnutzung verbundene Dienstleistungen zu erbringen. Auch wird Google diese Informationen gegebenenfalls an Dritte übertragen, sofern dies gesetzlich vorgeschrieben ist oder soweit Dritte diese Daten im Auftrag von Google verarbeiten.« Ob und inwieweit dies für einen Website-Betreiber relevant ist, muss jeder selbst entscheiden. Eine Alternative bieten Auswertungsprogramme, welche die Logfiles des ApacheWebservers auswerten. Ein bekannter Vertreter dieser Art ist der Webalizer.5 Das Problem hierbei liegt – wie oben beschrieben – darin, dass weder Apache noch Webalizer Zugriffe einzelnen Webseiten zuordnen können und so keine belast4 https://addons.mozilla.org/de/firefox/addon/1865 5 http://www.webalizer.com/
335
5.1
5
Optimierung und Monitoring
bare Aussage über die tatsächliche Zahl von Zugriffen möglich ist. Ob ein Abruf direkt im Sinne einer Page Impression oder nur indirekt durch automatisches Nachladen eines Skriptes erfolgt ist, kann durch Logfile-Analyse nicht ermittelt werden. Ebenso kann eine kontinuierliche Trendmessung durch eine Änderung an der Struktur der Webseiten leicht ad absurdum geführt werden. Führt ein Relaunch eines Webauftritts dazu, dass jede Seite wesentlich mehr Elemente vom Server benötigt, erhöht sich die Zahl der Zugriffe auf den Server allein durch die Umstellung der Website und nicht dadurch, dass mehr Benutzer auf die Seite zugreifen. Nichtsdestotrotz ist ein Tool wie Webalizer eine einfache Möglichkeit, rudimentäre Auswertungen über die Nutzung einer Website zu erstellen, und wenn Sie die Einschränkungen dieser Methode kennen und sich darüber im Klaren sind, spricht nichts dagegen, Logfiles mit dem Webalizer auszuwerten. Für den Hausgebrauch reicht das allemal. Webalizer ist als Paket für Ubuntu und Gentoo verfügbar: # sudo apt-get install webalizer # sudo emerge webalizer
Die Konfigurationsdatei liegt unter Ubuntu im Verzeichnis /etc/webalizer (webalizer.conf), unter Gentoo muss sie händisch erstellt werden. Eine Beispieldatei findet sich allerdings unter /usr/portage/distfiles/webalizer.conf.gz. Erstellen Sie unter Gentoo das Verzeichnis /etc/webalizer, und entpacken Sie die Datei in dieses Verzeichnis. # sudo mkdir /etc/webalizer # sudo zcat /usr/portage/distfiles/webalizer.conf.gz > / /etc/webalizer/webalizer.conf
Webalizer sollte regelmäßig über die archivierten Logdateien des Apache laufen. Wenn Sie die Logdateien jede Nacht rotieren, sollten Sie auch jede Nacht den Webalizer laufen lassen. Das Programm ist so intelligent, zusammenhängende Logdateien erkennen zu können und daraus eine kontinuierliche Historie zu erstellen. Die Grundkonfiguration beschränkt sich auf wenige Handgriffe und ist bei beiden Distributionen gleich. Die erste wichtige Direktive legt die Logdatei fest, die Webalizer zur Auswertung verwendet. LogFile /var/log/apache2/access.log.1
Geben Sie dort den Namen der Logdatei als Parameter an. Wenn Sie über Ihren Rotatelog-Mechanismus eine andere als die standardmäßig eingetragene Logdatei erzeugen, müssen Sie den Wert entsprechend anpassen. Praktisch ist, dass Web-
336
Monitoring
alizer auch eine gepackte Logdatei als Parameter akzeptiert. Das erspart das händische oder skriptgesteuerte Entpacken von rotierten Dateien. Webalizer entpackt die Datei selbständig für die Auswertung und packt diese nach der Arbeit wieder zusammen. Die folgende Direktive legt das Verzeichnis fest, in dem Webalizer die Ausgaben abspeichert. Da die Ausgaben im HTML-Format erzeugt werden, sollte sich das Verzeichnis im DocumentRoot Ihres Webservers befinden: OutputDir /var/www/webalizer
Für das Auge ist die Angabe ReportTitle Usage statistics for wichtig, denn damit können Sie die Überschrift der Statistik anpassen. An diesen Text wird der Wert der Direktive HostName angehängt. Das Problem, dass jede geladene Grafik einen Abruf erzeugt, lässt sich zumindest teilweise über die Direktive PageType abfangen. Mit dieser Direktive teilen Sie Webalizer mit, welcher Dateityp als Seitenabruf gewertet werden soll. Dabei sind auch Wildcards möglich. Allerdings lässt sich damit das Problem automatisch geladener Seiten nicht umgehen. PageType PageType PageType PageType PageType PageType PageType
htm* cgi phtml jsp php3 pl php
Die weiteren Einstellungen geben Ihnen die Möglichkeit, die Ausgabe des Webalizer individuell anzupassen. Verwenden Sie die installierte Konfigurationsdatei als Ausgangspunkt, darin ist jede Direktive ausführlich erläutert. Nach Fertigstellen der Konfiguration starten Sie den Webalizer. Je nach Größe der Logdateien kann ein Durchlauf recht lange dauern. Als Beispiel: Auf einem Intel Core 2 Duo mit 2,16 GHz dauert das Auswerten einer 7 Gigabyte großen Datei mit ca. 30.000.000 Logeinträgen knapp 8 Stunden – wobei eine solche Logdatei zugegebenermaßen nicht repräsentativ ist und von einem Hochlastwebserver stammt, der im Monat Abrufe in dreistelliger Millionenhöhe beantwortet. Nach Abschluss der Auswertung befinden sich im als Ausgabeverzeichnis konfigurierten Verzeichnis HTML- und PNG-Dateien, die über einen Webbrowser abgerufen werden können. Die Startseite zeigt die monatliche Übersicht (Abbildung 5.21).
337
5.1
5
Optimierung und Monitoring
Abbildung 5.21 Die Monatsübersicht des Webalizer
Nach Auswählen eines Monats führt Webalizer zur Detailansicht des Monats mit vielen Einzelansichten. In der Standardkonfiguration sind dies eine Übersicht über die Abrufe pro Tag (Abbildung 5.22) und pro Stunde (Abbildung 5.23) sowie verschiedene tabellarische Auswertungen der Zugriffe im betreffenden Monat. Insbesondere die Stundenübersicht ist für den Systembetreiber interessant, denn daraus lässt sich sehr genau ablesen, wann die Zeit des geringsten Zugriffs auf die Website ist. In dieser Zeit sollten notwendige Wartungsarbeiten stattfinden, die den Service unterbrechen oder das System belasten könnten. Typische Arbeiten sind das Rotieren von Logdateien, das – je nach Serverdienst – zu einem kurzen Ausfall des Dienstes führen kann. Ressourcenintensive Arbeiten wie ein Backup können dazu führen, dass die Antwortzeit des Webservers oder anderer wichtiger Dienste leiden. Neben den Statistiken über Abrufe generiert der Webalizer in der Standardkonfiguration auch noch eine Übersicht über die Länder, aus denen die Zugriffe stattgefunden haben (Abbildung 5.24). Das kann aus Marketinggründen interessant sein, etwa um den Erfolg der Internationalisierung der Website zu überprüfen.
338
Monitoring
Abbildung 5.22 Die Tagesübersicht über die Zugriffe
Abbildung 5.23 Die Stundenübersicht des Webalizer
Abbildung 5.24 Übersicht über die zugreifenden Länder
339
5.1
5
Optimierung und Monitoring
5.2
Optimierung
Trotz einer Überwachung mit Tools wie MRTG und Nagios kommt es beim Betrieb eines Servers immer wieder zu unerwarteten Problemen. Hardware kann plötzlich ausfallen, ein Angriff kann so viele Systemressourcen verbrauchen, dass die Antwortzeiten des Servers einbrechen, eine fehlerhaft programmierte Anwendung oder Webapplikation kann zu einem Speicherloch werden, ein unbedarfter Benutzer führt einen Befehl mit weitreichenden Folgen aus etc. Die Möglichkeiten sind vielfältig, und in solchen Fällen hilft nur eine schnelle Diagnose und Reaktion. MRTG ist für so einen Fall gänzlich ungeeignet, und Nagios hilft auch nur bedingt, denn es zeigt lediglich die Parameter an, für die es konfiguriert ist. Eine manuelle und flexible Diagnose ist damit nicht möglich. Es gibt eine Reihe von kleinen Programmen, die zumindest eine erste Diagnose in Fehlerfällen ermöglichen. Zunächst sind das die praktischen Helferlein, die jeder Linux-Distribution beiliegen wie top, df, netstat etc., mit denen sich die wichtigsten Parameter des Betriebssystems in Echtzeit auslesen lassen. Mit top beispielsweise kann man im Handumdrehen wildgewordene Prozesse identifizieren, die zu viel CPU-Zeit oder Speicher verbrauchen. Sind die betreffenden Prozesse identifiziert, kann es sinnvoll sein, dem Problem näher auf den Grund zu gehen. Bei einem Webserver unter Volllast ist dabei insbesondere und häufig der Apache von Interesse, bei einem LAMP-System darüber hinaus noch die MySQLDatenbank. Für beide Server existieren verschiedene Tools zur Echtzeitanalyse. top bietet zwar einen guten Überblick über die allgemeine Lage des Systems, stößt aber beispielsweise bei der Aussage über I/O-Aktivitäten an seine Grenzen. Die Kopfzeilen von top geben zwar an, wie die momentane Speicherlast und CPU-Belastung ist, detaillierte Informationen lassen sich dort allerdings nicht entdecken.
Abbildung 5.25 Die Systeminformationen von top
Wenn es etwas detaillierter sein darf, ist ein Tool wie sysstat enorm hilfreich, denn damit lassen sich Flaschenhälse und Lasterzeuger sehr genau identifizieren. Und genau wie bei top ist mit sysstat auch eine kontinuierliche Überwachung verschiedener Parameter über eine Shell möglich, was im Notfall eine große Hilfe für den Administrator darstellt.
340
Optimierung
5.2.1
apachetop
apachetop ist ein Programm, das aus der Accesslog-Datei des Apache eine Über-
sicht über die aktuell stattfindenden Seitenabrufe generiert und diese – wie der Namensvetter top – der Reihenfolge nach gruppiert. apachetop ist für Ubuntu und Gentoo als Paket verfügbar. Die Installation ist selbsterklärend: # sudo apt-get install apachetop
bzw. # sudo emerge apachetop
Nach der Installation ist das Programm verfügbar und wird mit der für die Analyse zu verwendenden Accesslog-Datei des Apache aufgerufen. Je nach Name und Verzeichnis müssen Sie den Aufruf entsprechend anpassen. Damit apachetop funktioniert, muss der Benutzer, mit dem Sie das Programm aufrufen, Leserechte auf der Accesslog-Datei besitzen. # apachetop /var/log/apache2/access.log
Nach dem Aufruf erscheint die Oberfläche von apachetop. Diese orientiert sich – wie der Name des Programms bereits suggeriert – an top (Abbildung 5.26).
Abbildung 5.26
Die Oberfläche von apachetop
Die Oberfläche zeigt die innerhalb der letzten 30 Sekunden am häufigsten abgerufenen Webseiten in der Übersicht an, sortiert nach Anzahl der Abrufe. In der Kopfzeile befinden sich Angaben über die Anzahl der Abrufe, das von den Abrufen erzeugte Transfervolumen, die prozentuale Anzahl der verschiedenen HTTPRückgabecodes und weitere statistische Angaben. Mit den Pfeiltasten können Sie in der Übersicht über die URLs navigieren und durch einen Rechtspfeil nähere Angaben zu der jeweils ausgewählten URL abrufen (Abbildung 5.27). Wie top ist auch apachetop höchst intuitiv. Falls Sie nähere Informationen zur Bedienung benötigen, hilft die Manpage weiter, der Aufruf mit dem Parameter –h oder Drücken der Taste (h), während apachetop läuft.
341
5.2
5
Optimierung und Monitoring
Abbildung 5.27 Detailinformationen zu einer URL
5.2.2
mytop
Analog zu top und apachetop hilft das Programm mytop beim Auffinden von Performanceproblemen bei einer MySQL-Datenbank. Genauso wie die beiden besagten Programme stellt mytop die aktuellen MySQL-Prozesse dar. Im Gegensatz zu apachetop liest das Programm die dazu benötigten Informationen aber nicht aus einer Logdatei, sondern fragt direkt den MySQL-Server ab. Das bedeutet, dass mytop nicht funktioniert, wenn der Server bereits die maximale Anzahl an Verbindungen geöffnet hat. Da es für Ubuntu und Gentoo jeweils ein mytop-Paket gibt, ist die Installation gewohnt einfach: # sudo apt-get install mytop
bzw. # sudo emerge mytop
Da sich mytop für die Analyse mit dem Datenbankserver verbindet, benötigt es zum Betrieb einen gültigen MySQL-Benutzer. Der Aufruf kann über die Kommandozeile erfolgen: # mytop –u root –p passwort –h localhost –d datenbank
Davon ist allerdings dringend abzuraten, da je nach Kernelversion die Kommandozeilenargumente im proc-Verzeichnis und in der Prozessliste zu sehen sind. Damit könnte ein lokaler Benutzer die Zugangsdaten für den MySQL-Server auslesen. Sinnvoller und einfacher ist das Verwenden der Konfigurationsdatei ~/.mytop. Diese kann durch die entsprechenden Dateisystem-Berechtigungen vor unbefugtem Zugriff geschützt werden, wenngleich das Abspeichern von Passwörtern im
342
Optimierung
Klartext in jedem Fall eine Sünde ist. Idealerweise legen Sie sich für die Arbeit mit mytop einen MySQL-Benutzer mit stark eingeschränkten Rechten zu, der zwar Zugriff auf die Prozessinformationen des Datenbankservers hat, aber keine Daten verändern kann. Das Format der mytop-Konfigurationsdatei ist das folgende: user=mytop pass=1234qwer host=localhost db=mysql delay=5
Beim Aufruf von mytop ohne weitere Parameter verwendet es die Datei ~/.mytop und greift mit den darin konfigurierten Werten auf den MySQL-Server zu.
Abbildung 5.28
5.2.3
Die Oberfläche von mytop
sysstat
In der Unix-Welt, insbesondere unter Solaris, ist die Toolsammlung sysstat für die Überwachung von Systemen schon lange ein Standard. sysstat besteht aus verschiedenen Programmen, wobei die wichtigsten iostat, pidstat und sar sind. Da eine Linux-Portierung von sysstat existiert und es auch Pakete für Ubuntu und Gentoo gibt, können Sie sysstat für eine schnelle, aber genaue Diagnose von Problemen über die Kommandozeile verwenden. Unter Ubuntu installieren Sie sysstat über das gleichnamige Paket: # sudo apt-get install sysstat
Nach der Installation sollten Sie den SAR-Daemon konfigurieren. Dieser Daemon sammelt kontinuierlich Systemparameter, die Sie bei Bedarf mit dem Programm sar abrufen können. Damit er Daten sammeln kann, muss er regelmäßig als Cron-Job laufen. Über den folgenden Befehl können Sie den Cron-Job automatisch einrichten lassen: # sudo dpkg-reconfigure sysstat
iostat Das Programm iostat gibt detaillierte Informationen über den Status der CPU und von I/O-Subsystemen aus. Ohne Parameter aufgerufen, zeigt iostat den aktuellen CPU-Status sowie den Durchsatz der lokalen Festplatten (Abbildung 5.30).
Abbildung 5.30
Standardausgabe von iostat
Alle Tools aus dem sysstat-Paket akzeptieren eine Zahl als Kommandozeilenparameter, die ein Intervall in Sekunden angibt, nach dem der betreffende Befehl erneut ausgeführt wird – in einer Endlosschleife. Der Befehl … # iostat 2
… bedeutet also, dass alle zwei Sekunden iostat ausgeführt und somit eine kontinuierliche Messreihe erzeugt wird. iostat ist insbesondere dann hilfreich, wenn top einen großen I/O-Wert anzeigt und man wissen möchte, an welcher Stelle so viel I/O erzeugt wird. Abbildung 5.31 zeigt einen solchen Fall. Das System zeigt eine hohe Festplattenaktivität an
344
Optimierung
und iostat demonstriert genau, auf welcher Festplatte die Aktivität stattfindet, und mit der Durchschnittsangabe in Byte pro Sekunde, wie viele Daten bewegt werden.
Abbildung 5.31
Festplattenaktivität mit iostat beobachtet
Interessant ist dies auch bei der Verwendung von NFS-Mounts, also Verzeichnissen, die über das NFS-Protkoll von einem anderen System eingebunden oder an ein anderes System exportiert werden. Gerade in Serverfarmen kommt dieses Verfahren häufig zum Einsatz. Gemeinsame Daten, z. B. eine von einer Farm von Webservern auszuliefernde Webapplikation, liegen auf einem NAS-Storage, das die Daten per NFS bereitstellt. iostat erlaubt über den Parameter -n auch die Ausgabe von Statistiken der NFS-Anbindungen eines Systems.
345
5.2
5
Optimierung und Monitoring
5.2.4
pidstat
Das Programm pidstat gibt detaillierte Informationen über die CPU-Verwendung der Prozesse aus. Ohne Parameter aufgerufen, zeigt pidstat eine Liste aller aktuellen Prozesse, deren PID und die CPU-Last der Prozesse an. # pidstat Linux 2.6.24-16-server (hardy2) 21:19:33 21:19:33 21:19:33 21:19:33 21:19:33 21:19:33 21:19:33 21:19:33 21:19:33 21:19:33 21:19:33 21:19:33 21:19:33 [...]
Eine wichtige Fähigkeit von pidstat ist, zu den einzelnen Prozessen auch deren I/O-Verhalten anzeigen zu können. Um zu sehen, wie viel I/O die einzelnen Apache-Prozesse erzeugen, rufen Sie pidstat mit dem Parameter –d auf: # pidstat -d -C apache2 Linux 2.6.24-16-server (hardy2) 21:27:55 21:27:55 21:27:55 21:27:55 21:27:55 21:27:55
Damit wird pidstat zu einem unentbehrlichen Informationssystem, um kurzfristigen Lastspitzen und Performanceproblemen auf die Schliche zu kommen. Nagios und MRTG zeigen Ihnen, dass etwas nicht stimmt – was nicht stimmt, müssen Sie noch immer zu Fuß herausfinden. Dabei sind die sysstat-Tools eine wertvolle Hilfe.
347
5.2
5
Optimierung und Monitoring
sar Das Programm sar ist die eierlegende Wollmilchsau der sysstat-Tools. So gut wie jeder Systemparameter – von CPU-Last über Speicheraktivität zu I/O, Sockets und Netzwerkinterfaces – kann von sar abgefragt und angezeigt werden. Der vom Installer angelegte Cron-Job speichert in 10-Minuten-Abständen einen Systemstatus, den Sie mit sar abrufen können.
Abbildung 5.32
Ausgabe von sar ohne Parameter
Einen Eindruck davon, wie viele Parameter sar anzeigen kann, bekommen Sie, wenn Sie in die Manpage schauen und nach der Erläuterung des Parameters -A suchen, mit dem alle von sar überwachten Systemparameter angezeigt werden können: This is equivalent n ALL -P ALL
to
specifying -bBcdqrRuvwWy -I SUM -I XALL -
Die Ausgabe von sar –A ist dementsprechend umfangreich. sar ist zwar ein wichtiger Bestandteil der sysstat-Tools, für eine schnelle Diagnose im Problemfall aber eher weniger geeignet. Die Tools iostat und pidstat sind die erste Wahl, wenn Sie gezielt nach Flaschenhälsen oder Performancebremsen suchen möchten. Der Cron-Job, der alle 10 Minuten sar ausführt und somit eine nachträgliche Überprüfung von Systemparametern ermöglicht, kostet nicht viele Ressourcen. Zusammen mit einem Monitoring über MRTG und/oder Nagios ist eine Überwachung mit sar allerdings wenig sinnvoll.
5.2.5
Festplattenstatus
Festplatten sind die Bauteile eines Computers, die dem größten mechanischen Verschleiß unterliegen. Damit zählen Festplatten auch zu den Bauteilen, die mit besonderer Sorgfalt überwacht werden sollten. Seit Ende der 90er Jahre existiert mit dem SMART-Standard eine Technik, mit der sich Festplatten selbst überwachen und ihren Zustand an den Rechner übermitteln können. SMART ist die Ab-
348
Optimierung
kürzung für Self-Monitoring, Analysis and Reporting Technology. SMART überwacht verschiedene Parameter einer Festplatte, wobei diese Parameter von Hersteller zu Hersteller unterschiedlich sind. Gängige Parameter sind die Temperatur der Platte, die Betriebszeiten und Informationen über fehlerhafte Bereiche. Was die Aussagekraft von SMART angeht, gibt es gegenläufige Meinungen. Im Februar 2007 haben die Google-Mitarbeiter Pinheiro, Weber und Barroso eine Untersuchung6 dazu durchgeführt und sind zu dem Ergebnis gekommen, dass 64 % der Festplattenausfälle im Vorfeld über SMART entsprechende Fehler gemeldet haben, bei 36 % erfolgten die Ausfälle ohne vorherige SMART-Meldung. Auch wenn SMART offensichtlich keine hundertprozentig sichere Vorhersagemöglichkeit bietet, sind 64 % jedoch bereits ein guter Wert – und da ohnehin jede Festplatte SMART unterstützt, ist das Überwachen der SMART-Meldungen durch das Betriebssystem in jedem Fall eine gute Idee. Unter Linux kann der SMART-Status mit den smartmontools überwacht werden. Diese sind für Ubuntu und Gentoo verfügbar: # sudo apt-get install smartmontools
bzw. # sudo emerge smartmontools
Das Programm zur Abfrage von SMART-Informationen ist smartctl. Um herauszufinden, ob Ihre Festplatte überhaupt SMART-fähig ist, können Sie mit smartctl den Status der Festplatten abfragen: # sudo smartctl -i /dev/sda smartctl version 5.37 [i686-pc-linux-gnu] Copyright (C) 2002-6 Bruce Allen Home page is http://smartmontools.sourceforge.net/ === START OF INFORMATION SECTION === Device Model: TOSHIBA MK4026GAX RoHS Serial Number: 15TY1471X Firmware Version: PA107E User Capacity: 40.007.761.920 bytes Device is: Not in smartctl database [for details use: -P showall] ATA Version is: 6 ATA Standard is: Exact ATA specification draft version not indicated Local Time is: Tue Sep 9 11:09:01 2008 CEST SMART support is: Available - device has SMART capability. SMART support is: Enabled 6 http://labs.google.com/papers/disk_failures.pdf
349
5.2
5
Optimierung und Monitoring
Falls die Festplatte keine SMART-Unterstützung bietet, handelt es sich entweder um ein sehr altes Modell (10 Jahre oder älter) oder Ihr Betriebssystem läuft in einer virtuellen Maschine. In diesem Fall ist kein Zugriff auf die Hardware möglich, was smartctl entsprechend kommentiert: # sudo smartctl -i /dev/sda smartctl version 5.37 [i686-pc-linux-gnu] Copyright (C) 20026 Bruce Allen Home page is http://smartmontools.sourceforge.net/ Device: VMware, VMware Virtual S Version: 1.0 Device type: disk Local Time is: Tue Sep 9 11:11:35 2008 CEST Device does not support SMART
Festplatten und Partitionen SMART gibt Auskunft über den Status einer Festplatte, nicht über den einer Partition. Daher müssen Sie als Argument für smartctl immer den Bezeichner der Festplatte (z. B. /dev/sda) übergeben, nicht den einer Partition (z. B. /dev/sda1). Die zweite Möglichkeit funktioniert in der Regel zwar auch, ist aber nicht korrekt, da Partitionen logische Einheiten auf einer Festplatte sind, die das Betriebssystem eingerichtet hat und die mit dem SMART-Status nichts zu tun haben.
Die einfachste Möglichkeit, den SMART-Status einer Festplatte abzufragen, ist die über den Kommandozeilenparameter –H (»Show Device SMART Health Status«). # sudo smartctl -H /dev/sda smartctl version 5.37 [i686-pc-linux-gnu] Copyright (C) 2002-6 Bruce Allen Home page is http://smartmontools.sourceforge.net/ === START OF READ SMART DATA SECTION === SMART overall-health self-assessment test result: PASSED
Das Schöne an dieser Ausgabe ist: Die relevanten Informationen passen in eine Zeile: # smartctl -H /dev/sda|grep result SMART overall-health self-assessment test result: PASSED
Damit ist dieser Befehl ohne weitere Modifikation dazu geeignet, von Nagios verwendet zu werden. Sie können den SMART-Status per NRPE abrufen, wenn Sie den folgenden Befehl in der nrpe.cfg definieren: command[check_smart]=’/usr/sbin/smartctl –H /dev/sda| grep result’
350
Optimierung
Eine ausführliche Ausgabe des SMART-Status erhalten Sie durch die Kombination der Parameter -H und –c, womit Sie im Fehlerfall eine genaue Diagnose des von SMART gemeldeten Fehlers erstellen können. Die smartmontools umfassen neben dem Programm smartctl auch den Daemon smartd. Dieser kann automatisch den SMART-Status der lokalen Festplatte(n) überwachen und bei Fehlern Benachrichtigungen versenden. Es ergibt allerdings wenig Sinn, neben der Überwachung mit einem Tool wie Nagios noch eine weitere Überwachungsinstanz zu etablieren. Sinnvoller ist es, die SMART-Überwachung durch ein eigenes Plugin in Nagios zu integrieren und damit auch die Benachrichtigungs- und Eskalationsmechanismen von Nagios zu verwenden.
351
5.2
»Linux is obsolete.« Andrew S. Tanenbaum
6
Hochverfügbarkeit
Die Anforderungen an einen produktiv genutzten Server sind hoch, nach Möglichkeit sollte ein System nicht ausfallen. Dass mögliche Fehlerquellen vielfältig sind und es daher genügend Ursachen dafür geben kann, dass ein System nicht mehr funktioniert, weiß jeder Administrator. Glücklicherweise gibt es Lösungen, die eine gewisse Hochverfügbarkeit ermöglichen, so dass der Ausfall eines Systems nicht zwangsläufig zu einem Ausfall von Diensten führt. Hochverfügbarkeit ist ein Thema, um das sich viele falsche Vorstellungen ranken. Hochglanzprospekte und Vertriebsmitarbeiter reden gerne von einer Verfügbarkeit von 99,99 % pro Jahr. Für den Betreiber eines Servers, der damit Dienste für Kunden erbringt, sind solche Angaben mit großer Vorsicht zu genießen. Vor allen Dingen sollten Sie sich als Dienstleister darüber im Klaren sein, was das Festlegen einer garantierten Hochverfügbarkeit in der Praxis bedeutet. Eine Verfügbarkeit von 99 % pro Jahr bedeutet, dass der betreffende Dienst 8672,4 Stunden im Jahr verfügbar sein muss. Damit ist eine Nichterreichbarkeit von 87,6 Stunden pro Jahr erlaubt. Fügt man hinter dem Komma eine 9 ein, garantiert damit also eine 99,9 %ige Verfügbarkeit im Jahr, reduziert sich die erlaubte Ausfallzeit auf nur noch 8,76 Stunden im Jahr! Die folgende Tabelle zeigt die erlaubten Ausfallzeiten pro garantierter Hochverfügbarkeit für unterschiedliche Zeiträume. 99 %
99,9 %
99,99 %
99,999 %
Stunden pro Jahr
87,6
8,76
0,876
0,0876
Minuten pro Jahr
5256
525,6
52,56
5,256
Stunden pro Monat
7,3
0,73
0,073
0,0073
Minuten pro Monat
438
43,8
4,38
0,438
Minuten pro Tag
14,4
1,44
0,144
0,0144
Tabelle 6.1 Hochverfügbarkeit und erlaubte Ausfallzeiten
353
6
Hochverfügbarkeit
Selbst bei einer 99 %igen Hochverfügbarkeit reduziert sich die tägliche erlaubte maximale Ausfallzeit auf 14,4 Minuten. Garantieren Sie Ihren Kunden eine Verfügbarkeit von 99,9 %, haben Sie eine erlaubte Ausfallzeit von 1,44 Minuten pro Tag. Denken Sie dabei nicht nur an unvorhergesehene Ausfälle. Die Nichterreichbarkeit eines Dienstes kann auch durch reguläre Wartungsarbeiten hervorgerufen werden. Es erscheint normalerweise mehrmals im Jahr ein Kernel-Update für Ubuntu und Gentoo. Das erfordert jedes Mal einen Neustart des Systems. Ein Neustart kann – wenn unerwartet, unerwünscht, aber nahezu unvermeidbar ein fsck anspringt und eine Partition auf Fehlerfreiheit überprüft – mehrere Minuten dauern. Ein Update eines Serverdienstes, die Erstellung einer neuen Konfiguration zu Testzwecken oder ein Relaunch einer Webapplikation können ebenfalls zu einer Unterbrechung des Dienstes führen. Zu ambitionierte Versprechen bezüglich der Verfügbarkeit können dann schnell zum Problem werden. Linux wäre nicht so erfolgreich, wenn es nicht auch und gerade für diese Problematik adäquate Hilfsmittel gäbe. Mit Xen steht eine mächtige und effiziente Virtualisierungslösung zur Verfügung, die einem Serverbetreiber das Einrichten virtueller Maschinen erlaubt, auf denen sich Entwickler und Administratoren austoben und nach Belieben neue Programme und Funktionen ausprobieren können, bevor sie auf das Produktivsystem wandern. Damit können Sie zumindest die Wahrscheinlichkeit manuell herbeigeführter Ausfälle und Systemstörungen minimieren. Um eine angemessene Hochverfügbarkeit herbeizuführen, steht mit Heartbeat eine Cluster-Software bereit, mit der sich im Handumdrehen aus zwei Linux-Systemen ein Hochverfügbarkeitscluster erstellen lässt. Damit sind Sie in der Lage, ein System mit Updates, neuer Hardware oder notwendigen Änderungen zu versorgen, während das andere System die produktiven Dienste ohne Unterbrechung anbietet. Eine hundertprozentige Hochverfügbarkeit bietet auch ein Cluster nicht, aber Verfügbarkeit von 99,9 % rückt damit zumindest von Seiten des Betriebssystems in greifbare Nähe. Andere Faktoren wie z. B. Stromversorgung und Internetanbindung sind davon natürlich nicht berührt.
6.1
Virtualisierung
Das Thema Virtualisierung ist in den letzten Jahren immer mehr in Mode gekommen. Im PC-Bereich wurde es durch das Produkt VMware und die gleichnamige Firma bekannt. 1998 gegründet, entwickelte VMware schon früh leistungsfähige Virtualisierungslösungen für PC-basierte Hardware, d. h. für Systeme, die auf
354
Virtualisierung
dem Intel-x86-Prozessor basieren. In den Anfangszeiten der Virtualisierung für die breite Masse waren entsprechende Produkte ausschließlich gegen Geld zu bekommen. Mittlerweile hat sich das Bild stark gewandelt. Neben VMware haben noch weitere große Firmen das Feld der Virtualisierung für sich entdeckt und damit einen recht heftigen Kampf um Marktanteile eröffnet. Ob durch Zukäufe oder eigene Entwicklungen – mittlerweile tummeln sich neben VMware Firmen wie Microsoft, Sun Microsystems und Citrix auf dem Markt der Virtualisierungslösungen. VMware selbst wurde von der Firma EMC aufgekauft, einem der weltweit führenden Anbieter von Storage-Lösungen. Konkurrenz belebt im Allgemeinen das Geschäft, und das gilt auch für die Anbieter von Virtualisierungslösungen. Waren die Produkte in der Anfangszeit noch teuer und nur zahlenden Kunden vorbehalten, hat sich das Bild in der Zwischenzeit stark gewandelt. Von jeder kommerziellen Virtualisierungslösung gibt es mindestens eine kostenlose Variante, in einigen Fällen sogar als Open-SourceProdukt. Selbst die Virtualisierungssoftware VirtualPC der Firma Microsoft ist kostenlos erhältlich, allerdings setzt die Benutzung das Vorhandensein eines Windows-Betriebssystems voraus, einen entsprechenden Obolus hat sich Microsoft also in jedem Fall vorher schon beim Kunden geholt. Neben den Produkten kommerzieller Anbieter und der Open-Source-Varianten einiger dieser Produkte existieren noch weitere Virtualisierungslösungen und Emulatoren auf Open-Source-Basis wie QEMU1 oder Bochs2, die aber weniger für den professionellen Einsatz geeignet sind als vielmehr für Einzelplatzanwendungen oder Entwicklungsarbeiten. Unter Linux hat sich das quelloffene Projekt Xen3 mittlerweile zum Standard unter den Virtualisierungslösungen entwickelt. Ursprünglich war Xen eine Entwicklung der Universität von Cambridge (Großbritannien). Daraus hat sich das Spin-Off XenSource entwickelt, das 2007 von Citrix, einem der führenden Anbieter für Remote-Zugangssoftware, übernommen wurde. Am Status der Xen-Software als Open-Source-Produkt hat der Wechsel der Eigentümer (bisher) nichts geändert. Xen scheint sich zu einem firmenübergreifenden Standard zu entwickeln. Zahlreiche große Firmen arbeiten an der Unterstützung von Xen, selbst Microsoft plant dies für zukünftige Versionen von Windows. 2006 vereinbarten VMware und XenSource eine Zusammenarbeit, um ein einheitliches Interface für Virtualisierungslösungen zu schaffen.
Virtualisierung kann verschiedene Themen umfassen und von Netzwerkebene bis zur Storage-Virtualisierung alle möglichen Bereiche von IT-Systemen umfassen. In diesem Buch bezeichnet Virtualisierung die Möglichkeit, innerhalb eines laufenden Betriebssystems ein weiteres oder mehrere weitere Betriebssysteme zu starten. Diese weiteren Betriebssysteme greifen dabei nicht unmittelbar auf die Hardwareressourcen des Systems zu, sondern bekommen von der Virtualisierungssoftware ein Interface zur Verfügung gestellt, über das sie mit der Hardware kommunizieren. Es existieren verschiedene Arten der Virtualisierung, abhängig von der eingesetzten Virtualisierungssoftware und der eingesetzten Hardware. In diesem Buch ist Xen die Virtualisierungslösung der Wahl, denn nicht zuletzt durch die Aufnahme in den Linux-Kernel ist Xen anderen Virtualisierungslösungen unter Linux mindestens eine Nasenlänge voraus. Obendrein ist Xen unglaublich performant und flexibel, verglichen mit der Konkurrenz in Form von beispielsweise VMware oder Virtualbox. Die genaue Funktionsweise von Xen erläutert Abschnitt 6.1.1. Virtualisierung ist lange ein Nischenthema gewesen. Für einen Entwickler z. B. war es schon immer praktisch, auf seinem Entwicklungssystem eine virtuelle Maschine mit einem Testsystem betreiben zu können, auf dem er Dinge ausprobieren kann, ohne damit das Entwicklungssystem zu stören. Mittlerweile hat sich das Thema Virtualisierung zu einem der zentralen Themen der modernen IT entwickelt. Die beiden großen Prozessorhersteller Intel und AMD haben Prozessoren entwickelt, die Virtualisierung direkt auf Hardware-Ebene unterstützen (Intel VT und AMD IOMMU). Dies erlaubt das performante Ausführen von Betriebssystemen in einer Virtualisierungsumgebung, ohne dass diese Betriebssysteme speziell dafür modifiziert werden müssen und ohne dass die Virtualisierungsumgebung Anfragen von den Gastsystemen an die Hardware über die Emulationsschicht abfangen und übersetzen muss. Einige Begriffe zur Virtualisierung Im Bereich der Virtualisierung begegnen Ihnen einige möglicherweise unbekannte Begriffe. Als Host bezeichnet man das (Betriebs-)System, auf dem die jeweilige Virtualisierungslösung läuft. Ein Gast- oder Guest-System ist ein Betriebssystem, das innerhalb einer Virtualisierungslösung läuft. Auf einem Host können, je nach Ausstattung der Hardware, verschiedene Gast-Systeme laufen.
Der Vorteil beim Einsatz von Virtualisierung liegt auf der Hand: Auf einer ausreichend dimensionierten Hardware können parallel mehrere Betriebssysteme laufen. So lassen sich gerade im professionellen Umfeld Kosten dadurch vermeiden, dass nicht jeder Server eine eigene Hardware benötigt. Das spart Anschaffungs- und Wartungskosten für die Hardware, Platz im Rechenzentrum, und – gerade in jüngs-
356
Virtualisierung
ter Zeit von erhöhter Bedeutung – Strom (Green IT). Die Kosten für die physische Bereitstellung für IT lassen sich durch den Einsatz von Virtualisierung massiv senken. Neben diesem augenfälligen Vorteil gibt es viele weitere Vorteile, wie z. B. die effiziente Nutzung vorhandener Hardware, vereinfachte Administration etc. Es gibt beim Thema Virtualisierung allerdings auch einige Nachteile zu bedenken. Jedes Host-System stellt einen Single-Point-of-Failure da. Fällt ein Host-System aus, sind nicht nur das System selbst, sondern auch alle Gast-Systeme betroffen. Darüber hinaus muss die Hardware eines Host-Systems leistungsfähig genug sein, um allen Gast-Systemen ausreichende Ressourcen bieten zu können. Und zu guter Letzt wird das Thema Sicherheit im Bereich der Virtualisierung häufig vergessen oder beschönigt. Nach der landläufigen Meinung sind Host- und GastSysteme sowie Gast-Systeme untereinander vollkommen gegeneinander abgeschirmt. Ein Sicherheitsvorfall auf einem Gast-System hat daher – so die Annahme – keine Auswirkungen auf andere Gast-Systeme oder das Host-System. Das Gegenteil ist richtig: Hosts und Gäste teilen sich dieselben Ressourcen, und in der Vergangenheit sind bereits öfter Sicherheitslücken aufgetaucht, über die ein Angreifer über ein Gast-System Zugriff auf das Host-System erlangen konnte. Ist ein Host-System erst einmal kompromittiert, steht dem Angreifer der Zugriff auf alle darauf laufenden Gast-Systeme offen. Virtualisierung bringt daher nicht nur Vorteile, sondern birgt handfeste Risiken. Bei Systemen mit unterschiedlichem Schutzbedarf, die gegeneinander gekapselt sein müssen, ist Virtualisierung daher kein Mittel der Wahl. Hier bleibt nur der altmodische Weg über getrennte Hardware und eine ausreichende Separierung auf Netzwerkebene. Wozu Virtualisierung auf dem eigenen Server? Auf einem eigenen Server ergibt Virtualisierung aus Sicherheitsgründen keinen Sinn. Allerdings ist ein virtuelles System für Testzwecke enorm hilfreich. Angenommen, Sie möchten eine neue Version Ihrer Webapplikation testen, die möglicherweise Änderungen am Betriebssystem oder an den Serverdiensten erfordert. Ihr Produktivsystem sollten Sie dafür nicht verwenden, denn wenn der Test schiefgeht, ist es mit der Verfügbarkeit schnell dahin. Auch lassen sich Änderungen wie z. B. die Installation neuer Paketversionen o. Ä. meist nur schwer wieder rückgängig machen. Das Vorhandensein eines virtuellen Systems, auf dem Sie alle notwendigen Änderungen ohne Gefahr für das Produktivsystem ausprobieren können, ist da enorm hilfreich. Selbst wenn das System durch Ihre Aktivitäten komplett unbrauchbar geworden ist, hat das keine Auswirkungen auf das produktive System. Im Zweifelsfall löschen Sie einfach das virtuelle System und legen sich ein neues an – aus dem hoffentlich vorher angelegten Backup. Eine andere Möglichkeit wäre natürlich das Verwenden eines zweiten Systems, aber das kostet Geld. Virtualisierung mit Xen hingegen ist garantiert kostenfrei.
357
6.1
6
Hochverfügbarkeit
6.1.1
Xen – das Konzept
Xen besteht – wie andere Virtualisierungslösungen auch – aus einem Host-System und verschiedenen Gast-Systemen, die auf diesem Host-System laufen können. Dabei verwendet Xen eine eigene Nomenklatur. Ein System, egal ob Host oder Gast, wird als Domäne oder Dom bezeichnet. Die Host-Domäne trägt immer den Namen Domain0 oder Dom0, ein Gast-System wird als DomainU oder DomU bezeichnet. Die Dom0 wird über einen entsprechend konfigurierten Kernel gestartet. Für Ubuntu ist ein entsprechend vorbereiteter Kernel über den Paketmanager erhältlich. Unter Gentoo ist die Verwendung von Xen durch das eigene Übersetzen aller erforderlicher Komponenten einschließlich Kernel ebenfalls kein Problem. Innerhalb der Dom0 verwaltet der Prozess xend alle Aktivitäten der XenUmgebung. Im Gegensatz zu den anderen gängigen Virtualisierungslösungen stellt Xen den Gast-Systemen eine Virtualisierungsschnittstelle zur Verfügung, die bestimmte Zugriffe auf die Hardware verbietet. Da dies für die Gast-Systeme kein normales Verhalten darstellt, müssen alle Gast-Systeme, die unter Xen laufen sollen, so modifiziert werden, dass sie mit der Abstraktionsschicht von Xen kommunizieren können. Für quelloffene Systeme ist das kein Problem, und es existieren für Linux, OpenSolaris und verschiedene BSD-Derivate bereits entsprechend modifizierte Kernel. Dieses als Paravirtualisierung bezeichnete Verfahren lässt proprietäre Betriebssysteme wie Windows oder OS X außen vor, da sich diese nicht ohne den Hersteller modifizieren lassen. Anders verhält es sich, wenn Xen auf einem Prozessor mit Hardware-Virtualisierung, also VT oder IOMMU, betrieben wird. In diesem Fall können die Gast-Systeme direkt auf die Virtualisierungsfunktionen der Hardware zugreifen, und auch der Xen-Host muss nicht mit einem speziellen Kernel gestartet werden. Die GastSysteme werden bei einem solchen Setup als HVMs bezeichnet, als Hardware Virtual Machines. Hardware-Virtualisierung oder nicht? Wenn Sie nicht sicher sind, ob Ihr System Hardware-Virtualisierung unterstützt, hilft Ihnen der Linux-Kernel weiter. Mit dem Befehl cat /proc/cpuinfo bekommen Sie detaillierte Informationen über die CPU Ihres Systems. Wenn im Abschnitt flags das Schlüsselwort vms (Intel-CPU) oder vmx (AMD-CPU) auftaucht, verwenden Sie eine CPU mit Hardware-Virtualisierung.
6.1.2
Xen unter Ubuntu
Unter Ubuntu installieren Sie für Xen das Paket ubuntu-xen-server. apt-get installiert in der Folge eine ganze Reihe von Paketen, unter anderem auch einen
358
Virtualisierung
neuen Kernel mit Xen-Unterstützung. Um diesen zu aktivieren, starten Sie nach der Installation das System neu und wählen im Grub-Menü den Xen-Kernel aus: Xen 3.2 / Ubuntu 8.04.1, kernel 2.6.24-19-xen
Um nach dem Systemstart herauszufinden, ob der Xen-Kernel aktiv ist, können Sie die Version des aktiven Kernels mit uname abfragen: # uname -r 2.6.24-19-xen
Abgesehen von der Versionsnummer, die sich ohnehin bei jedem Kernel-Update ändert, sind die drei letzten Buchstaben wichtig. Wenn der Xen-Kernel korrekt gestartet ist, kann es unter Ubuntu 8.04 sein, dass das System keine korrekte Netzwerkverbindung mehr hat. Falls das der Fall ist, prüfen Sie mit ifconfig, ob das System ein neues Interface mit der Bezeichnung peth0 besitzt. Dies ist das Interface der Bridge, die Xen verwendet, damit die Gast-Domains über die Netzwerkschnittstelle der Dom0 auf das Netzwerk zugreifen können. Netzwerkprobleme unter Hardy Unter Ubuntu 8.04 scheint es mit den aktuellen Xen-Paketen (Version 3.2) häufiger Probleme mit der Netzwerkkonfiguration zu geben. Vor Erscheinen der finalen Hardy-Version gab es einige Bugs in diesem Bereich, und auch jetzt, mit Version 8.04.1, scheinen noch immer nicht alle Probleme behoben zu sein. In Foren ist häufig von Problemen zu lesen, hinter dem Gateway liegende Hosts erreichen zu können. Im Selbstversuch konnte ich das Problem einige Male replizieren – es lag daran, dass nach dem Start des Systems zwei Standardrouten gesetzt waren, eine auf dem physischen Interface eth0 und eine auf dem Bridge-Interface peth0. Das Löschen der Route auf dem Bridge-Interface bringt in diesem Fall schnelle Abhilfe: # sudo route del default peth0
Nach der Installation der Pakete können Sie in der Datei /etc/xen-tools/xentools.conf die Vorgaben für die Installation virtueller Maschinen – DomUs – festlegen. Wenn Sie bereits mit Virtualisierungslösungen wie VMware oder Virtualbox vertraut sind, wird Ihnen die Art der Erstellung neuer virtueller Maschinen unter Xen möglicherweise fremd erscheinen, denn in den Xen-Tools als Installationskandidaten konfigurierte Betriebssysteme können vollautomatisch installiert werden. Die Grundlage für die Installation legen Sie in der Konfiguration der Xen-Tools fest. Für eine Installation von Ubuntu 8.04 als DomU in einem Loopback-Image benötigen Sie die folgenden Einstellungen in der Datei /etc/xen-tools/ xen-tools.conf: Zunächst müssen Sie ein Verzeichnis festlegen, in dem Xen die virtuellen Maschinen ablegt. Xen bietet die Möglichkeit, virtuelle Maschinen in eigene Partitionen
359
6.1
6
Hochverfügbarkeit
zu installieren oder in Imagedateien. Das Verwenden von Image-Dateien ist die flexibelste Lösung, da Sie dafür keine Änderungen an der Partitionierung des Systems vornehmen müssen. Für den Hausgebrauch reicht eine DomU in einem Image vollkommen. Wenn Sie allerdings mehrere DomUs mit hohen Ansprüchen an die Performance auf einem System betreiben möchten, sollten Sie über den Einsatz eigener Partitionen für die DomUs nachdenken. In diesem Beispiel ist das Verzeichnis /home/xen das Basisverzeichnis für alle virtuellen Maschinen: dir = /home/xen
Xen kennt verschiedene Methoden, um ein Gast-System zu installieren. Wenn Installationsarchive lokal verfügbar sind, kann Xen diese verwenden und das System durch Kopieren der Daten erstellen. Für Debian-Systeme steht die Installation via debootstrap zur Verfügung. Damit erstellt Xen ein vollständig neues System mit aus dem Netz geladenen Paketen. Für die Installation von Ubuntu als DomU ist diese Methode die erste Wahl: install-method = debootstrap
Über die Direktive dhcp können Sie festlegen, ob das Gast-System seine IPAdresse über DHCP beziehen soll. dhcp = 1
Wenn Sie eine feste IP-Adresse vergeben möchten, setzen Sie diese Direktive auf 0 und konfigurieren die IP-Adresse über die Direktiven ip, gateway, netmask und broadcast. Im Bereich von Serverfarmen, wo eine frisch installierte DomU immer dieselbe IP-Adresse haben soll, bis sie über ein Management-System eine individuelle IP-Adresse zugewiesen bekommt, ist das Festlegen einer festen IPAdresse sinnvoll. Um beim Installationsvorgang interaktiv ein root-Passwort für die neue DomU festlegen zu können, setzen Sie die Direktive passwd auf 1: passwd = 1
Über die folgenden Direktiven legen Sie die Rahmenbedingungen für die virtuelle Maschine fest, also den maximalen Festplattenplatz, RAM, die Größe des Swap-Speichers, das Dateisystem, die zu installierende Distribution und die Art der anzulegenden Images. Bei den letzteren existieren zwei Varianten. Sparse Images belegen immer nur den maximal vom Gast-System benötigten Platz und wachsen bei Bedarf mit – bis zur mit der Direktive size festgelegten Größe. Damit belegt ein Gast-System auch nur so viel Festplattenplatz, wie es benötigt. Full Disk Images reservieren schon zur Installationszeit den gesamten erlaubten Festplattenplatz, ein Gast-System belegt also immer den über size definierten
360
Virtualisierung
Platz. Der Vorteil von Sparse Images liegt auf der Hand, allerdings wird damit erkauft, dass die Änderung der Größe im laufenden Betrieb Performance kostet. Für den Hausgebrauch oder eine einzelne DomU zu Testzwecken ist ein Sparse Image daher immer das erste Mittel der Wahl; in Hochlastumgebungen sollten Sie hingegen mit Full Disk Images operieren, um die Systembelastung durch Festplatten-I/O zur Vergrößerung der Images zu vermeiden. size memory swap fs dist image
= = = = = =
4Gb 256Mb 256Mb ext3 hardy sparse
# # # # # #
Disk image size. Memory size Swap size use the EXT3 filesystem for the disk image. Default distribution to install. Specify sparse vs. full disk images.
Für das zu verwendende Dateisystem können Sie über die folgende Direktive die gewünschten Optionen festlegen. Orientieren Sie sich dabei im Zweifelsfall an den Einstellungen des Host-Systems, einsehbar in der Datei /etc/fstab. ext3_options
= noatime,nodiratime,errors=remount-ro
Die Direktive disk_device legt das von der DomU zu verwendende FestplattenDevice fest. Der Wert sollte auf dem voreingestellten Standard verbleiben. disk_device
= xvda
#default
Die Version des von der DomU zu verwendenden Kernels ermittelt Xen vom laufenden System (andere Werte möglich): kernel = /boot/vmlinuz-`uname -r` initrd = /boot/initrd.img-`uname -r`
Zum Schluss legen Sie noch den oder die Mirror fest, von dem bzw. denen Xen bei der Installation die benötigten Pakete laden soll: mirror = http://gb.archive.ubuntu.com/ubuntu/
Damit ist die Konfiguration komplett. Das Erzeugen einer neuen DomU mit der vorliegenden Konfiguration als Grundlage stoßen Sie über den Befehl xen-create-image an: # time xen-create-image --hostname=hardy_virt General Information -------------------Hostname : hardy_virt Distribution : hardy Partitions : swap 256Mb (swap) / 4Gb (ext3) Image type : sparse
Networking Information ---------------------IP Address : DHCP [MAC: 00:16:3E:9E:45:E3] Creating partition image: /home/xen/domains/hardy_virt/swap.img Done Creating swap on /home/xen/domains/hardy_virt/swap.img Done Creating partition image: /home/xen/domains/hardy_virt/disk.img Done Creating ext3 filesystem on /home/xen/domains/hardy_virt/disk.img Done Installation method: debootstrap Done Running hooks Done No role scripts were specified. Skipping Creating Xen configuration file Done Setting up root password Enter new UNIX password: Retype new UNIX password: passwd: password updated successfully All done Logfile produced at: /var/log/xen-tools/hardy_virt.log real 3m0.666s user 1m13.609s sys 0m23.377s
Durch Voranstellen des Befehls time können Sie überprüfen, wie viel Zeit die Installation benötigt. In diesem Fall, auf einem Intel Pentium M 1,86 GHz mit 2 GB RAM, sind das knapp drei Minuten, ein sportlicher Wert. Die Laufzeitkonfiguration der neuen virtuellen Maschine befindet sich nach der Installation im Verzeichnis /etc/xen in der Datei mit dem Namen der virtuellen Maschine, in diesem Beispiel also hardy_virt.cfg.
362
Virtualisierung
Vorsicht Falle! Aufgrund eines Bugs erzeugt Xen unter Ubuntu 8.04 eine fehlerhafte Konfigurationsdatei für neue Maschinen. Die Zuordnung der Images der virtuellen Maschine im Abschnitt disk ist falsch. Tauschen Sie für beide Images, das Root- und das Swap-Image, die Quelle file: gegen tap:aio: aus. Falsch: file:/home/xen/domains/hardy_virt/swap.img,xvda1,w file:/home/xen/domains/hardy_virt/disk.img,xvda2,w
Anschließend können Sie mit dem Programm xm die DomU starten. xm ist das Benutzer-Interface für die Interaktion mit Xen und den verschiedenen Domains. # sudo xm create hardy_virt.cfg Using config file "./hardy_virt.cfg". Started domain hardy_virt
Um sich mit der DomU zu verbinden, rufen Sie xm mit dem Parameter console und dem Namen der DomU auf, und Sie erhalten eine Root-Shell auf dem neuen System: # xm console hardy_virt hardy_virt login: root Password: Linux hardy_virt 2.6.24-19xen #1 SMP Thu Aug 21 03:09:02 UTC 2008 i686 [...]
Das System ist ein vollwertiges, eigenständiges Linux-System, eine echte virtuelle Maschine. Die in der Konfiguration festgelegten Parameter können Sie mit den Bordmitteln überprüfen. root@hardy_virt:~# df -h Filesystem Size /dev/xvda2 4.0G varrun 129M varlock 129M udev 129M devshm 129M
Um die Xen-Konsole zu verlassen, drücken Sie (Strg) + (¡). Beachten Sie bei der Arbeit mit Xen, dass so gut wie alle Aktionen Root-Rechte benötigen, worauf Xen und seine Tools allerdings auch hinweisen: Error: Most commands need root access. Please try again as root.
Das Programm xm ist ein mächtiges Werkzeug für den Umgang mit den Domains eines Systems. Eine Liste der möglichen Befehle gibt der Kommandozeilenparameter help aus: # xm help Usage: xm <subcommand> [args] Control, list, and manipulate Xen guest instances. xm full list of subcommands: console Attach to 's console. create Create a domain based on . new Adds a domain to Xend domain management delete Remove a domain from Xend domain management. destroy Terminate a domain immediately. domid Convert a domain name to domain id. domname Convert a domain id to domain name. dump-core Dump core for a specific domain. list List information about all/some domains. mem-max Set the maximum amount reservation for a domain. mem-set Set the current memory usage for a domain. migrate Migrate a domain to another machine. [...]
Eine Übersicht über die aktiven Domains erhalten Sie über den Schalter list: # sudo xm list Name ID Domain-0 0 hardy_virt 1
Mem 1764 256
VCPUs 1 1
State r-----b----
Time(s) 314.3 10.8
Um die gestartete DomU hardy_virt herunterzufahren, benutzen Sie den Schalter shutdown: # sudo xm shutdown hardy_virt
Arbeit mit der DomU Auch wenn die Installation erstaunlich kurz und unkompliziert ist – verglichen zumindest mit der Installation von Ubuntu in VMware oder Virtualbox –, steht Ihnen mit der erzeugten DomU eine echte virtuelle Maschine zur Verfügung. Alle Änderungen und Arbeiten, die Sie an dieser Maschine vornehmen, haben keine Auswirkungen auf das HostSystem. Installieren Sie einen SSH-Server für den Remote-Zugang, probieren Sie eine neue Apache-Version aus etc.
364
Virtualisierung
Vor gravierenden Änderungen am Gast-System sollten Sie eine Sicherheitskopie der Imagedatei anlegen. Falls das Gast-System durch einen Fehler unbrauchbar wird, können Sie dann durch Zurückkopieren der Sicherung den alten Zustand wiederherstellen. Denken Sie beim Erstellen der Sicherheitskopie aber daran, das Gast-System vorher herunterzufahren, sonst kopieren Sie einen inkonsistenten Datenbestand.
6.1.3
Xen unter Gentoo
Xen ist grundsätzlich auch unter Gentoo lauffähig. Entsprechende Pakete sind verfügbar und können über den Paketmanager installiert werden – zum Zeitpunkt der Manuskripterstellung waren sie allerdings noch maskiert, was auf mögliche Probleme hindeutet. Der Teufel steckt in der Tat im Detail, und zwar sehr tief. Für die Installation müssen Sie nicht nur einen neuen Kernel erstellen und dann Xen installieren, sondern das gesamte System neu übersetzen. Der Grund dafür liegt im Verhalten der TLSBibliothek der glibc. Die TLS-Bibliothek, die der Standard-Kernel verwendet, führt in Zusammenarbeit mit dem Xen-Kernel zu einem massiven PerformanceEinbruch, da Xen eine eigene Art des Speicherzugriffs verwendet, der mit der Speicherverwaltung der TLS-Bibliothek kollidiert. Das Übersetzen des gesamten Systems dauert mindestens genauso lange wie die initiale Installation des Systems. In der Regel wird die Zeit aber wesentlich länger sein, da dem System nach der Installation ja noch eine Reihe weiterer Pakete hinzugefügt worden sind. Der Compiler ist äußerst anspruchsvoll in Bezug auf seinen Ressourcenverbrauch, so dass das System während des Übersetzungsvorgangs kaum benutzbar sein wird. Liegt das letzte emerge world schon länger zurück, offenbart sich an dieser Stelle dann eine der größten Schwächen von Gentoo: Paketstrukturen haben sich geändert, Konfigurationen neuer Programmversionen sind nicht mehr mit denen der installierten Versionen kompatibel etc. Das Ergebnis ist in den meisten Fällen ein System, das den nächsten Neustart nicht übersteht. Mit viel Geduld und Handarbeit lässt es sich meist wieder in Gang bringen, aber diese vage Hoffnung eignet sich kaum als Grund, den Vorgang optimistisch auf einem produktiv genutzten System durchzuführen. Hinzu kommt, dass die Konfiguration des Xen-Kernels durch eine wenig aussagekräftige Dokumentation nicht trivial ist. Wenn das System das emerge world überlebt hat, fängt die Konfiguration des Kernels an. Dies artet regelmäßig in ein Trial-and-Error-Spiel aus und zieht zahlreiche Neustarts des Systems nach sich. Zusammenfassend muss die Einrichtung von Xen unter Gentoo auf einem produktiv genutzten System als nicht empfehlenswert bezeichnet werden. Die benötigten Pakete sind durch die Maskierung nicht für den Allgemeinbetrieb zugänglich, und das Vorbereiten des Systems für den Xen-Betrieb erfordert mindestens
365
6.1
6
Hochverfügbarkeit
tagelange Konfigurationsorgien. Die schlechte Dokumentation steuert ein Übriges bei. Mit ausreichend Geduld und Erfahrung ist der Betrieb von Xen unter Gentoo möglich. Spätestens beim nächsten Kernel-Update, das dann nicht nur die Dom0, sondern auch die DomUs betrifft, muss der Compiler wieder arbeiten, was auf einem produktiven System zu enormen Performance-Einbußen führt. Wenn Sie Xen verwenden möchten, sollten Sie daher für diesen Zweck lieber auf Ubuntu oder eine andere Distribution mit der Unterstützung von Binärpaketen wechseln. Spätestens eine Meldung wie diese sollte nachdenklich genug stimmen: This profile has not been tested thoroughly and is not considered to be a supported server profile at this time. For a supported server profile, please check the Hardened project (http://hardened.gentoo.org). This profile is merely a convenience for people who require a more minimal profile, yet are unable to use hardened due to restrictions in the software being used on the server. This profile should also be used if you require GCC 4.1 or Glibc 2.4 support. If you don't know if this applies to you, then it doesn't and you should probably be using Hardened, instead.
6.1.4
Sicherheit
Die Xen-Dokumentation besitzt einen eigenen Abschnitt über Sicherheit, allerdings ist dieser erstaunlich kurz und befasst sich weitestgehend mit der netzwerktechnischen Separierung von Xen-Domains durch Firewalls. Dies ist natürlich ein wichtiges Thema, da jede Domain als ein eigenes System betrachtet werden muss, allerdings beim Betrieb einer einzelnen DomU als Testsystem nur von untergeordneter Bedeutung. Der wohl wichtigste Aspekt ist die Absicherung der Dom0. Zugriffe auf diese Domain sollten so restriktiv wie möglich gehandhabt werden, denn kann ein Angreifer die Dom0 kompromittieren, hat er damit auch Zugriff auf alle DomUs. Sind ausreichend Hardwareressourcen vorhanden, können Sie darüber nachdenken, die produktiven Serverdienste nicht auf der Dom0 zu betreiben, sondern auf einer eigenen DomU. Diese können Sie über Heartbeat (siehe Abschnitt 6.2.1) mit einer weiteren DomU zu einem Cluster verbinden und so auf einem System eine Hochverfügbarkeit herstellen, die zumindest Ausfälle auf Software-Ebene abfängt und Wartungsarbeiten am Betriebssystem ohne Ausfall der Dienste ermöglicht. Darüber hinaus sollten Sie eine DomU nicht als ein vollständig abgeschlossenes System betrachten und daher sämtliche Sicherheitsmaßnahmen unterlassen. Wie in der Einführung zum Abschnitt 6.1 beschrieben, sind in der Vergangenheit
366
Der Linux-Cluster
immer wieder Sicherheitslücken in Virtualisierungslösungen aufgetaucht, über die ein Angreifer über ein kompromittiertes Gast-System auch den Host attackieren konnte. Lassen Sie daher bei der betriebssystemseitigen Konfiguration der DomUs größte Sorgfalt walten, und wenden Sie alle Regeln der Systemhärtung und -sicherung an, um Angreifern keinen Angriffsvektor zu bieten.
6.2
Der Linux-Cluster
Sobald ein System hochverfügbar sein soll, ist es Zeit, über den Betrieb eines Clusters nachzudenken. Ein Cluster ist ein Zusammenschluss mehrerer Systeme, die über eine Clustersoftware miteinander kommunizieren und gleich- oder wechselseitig Dienste anbieten. Ein Hochverfügbarkeitscluster besteht in der Regel aus zwei oder mehr Systemen, von denen eins aktiv ist und den oder die hochverfügbaren Dienste anbietet. Die weiteren Systeme in dem Cluster überwachen den Status des aktiven Systems. Fällt das aktive System aus, kann ein anderes System im Cluster den Dienst übernehmen. Neben Hochverfügbarkeitsclustern gibt es noch Rechencluster, in denen Systeme zur Erhöhung der Leistung zusammengeschaltet werden und sich Arbeiten untereinander aufteilen. Für den Betrieb eines hochverfügbaren Servers sind Rechencluster in der Regel nicht relevant. Ausnahmen können Rechencluster für Datenbankserver sein, in denen sich parallel arbeitende Systeme die Last teilen. In diesem Abschnitt wird die Einrichtung eines Hochverfügbarkeitsclusters gezeigt. Gerade im Webumfeld sind Hochverfügbarkeitscluster von großer Bedeutung, da der Ausfall einer gut frequentierten Website von den jeweiligen Benutzern unmittelbar registriert wird und schnelle Hilfe in einem solchen Fall nottut. Um die Leistung von Webservern zu verbessern, wird man nicht zu einem Rechencluster greifen, sondern parallel arbeitende Webserver über einen Loadbalancer ansteuern, da sich Webserver aufgrund des zustandslosen HTTP-Protokolls auch ohne Cluster leicht in ganze Serverfarmen skalieren lassen. Im Folgenden bezieht sich der Begriff »Cluster« stets auf einen Hochverfügbarkeitscluster. Die in einem Cluster zusammenarbeitenden Systeme werden als Nodes oder Knoten bezeichnet. In einem Cluster gibt es stets einen Master-Node und einen SlaveNode. Der Master-Node ist standardmäßig aktiv und betreibt die hochverfügbaren Dienste. Der Slave-Node übernimmt diese Dienste, sobald er registriert, dass der Master-Node nicht mehr erreichbar ist. Ein über einen Cluster hochverfügbar gestalteter Dienst kann eine IP-Adresse sein, die an den jeweils aktiven Node gebunden ist, oder ein oder mehrere Dienste wie der Apache-Webserver, ein Datenbankserver, kurz: Jedes ausführbare Programm kann von einem Cluster als Dienst verwaltet und somit hochverfügbar gestaltet werden.
367
6.2
6
Hochverfügbarkeit
6.2.1
Heartbeat
Für Linux steht mit der GPL-Software Heartbeat des Linux-HA-Projektes4 eine schlanke und effiziente Cluster-Software zur Verfügung. Die Buchstaben HA im Projektnamen stehen für High Availability (Hochverfügbarkeit) und stehen für den Sinn des Projektes, nämlich hochverfügbare Systeme mit Linux zu realisieren. Heartbeat kann in zwei verschiedenen Modi betrieben werden. Der traditionelle Modus unterstützt lediglich Cluster mit zwei Nodes. Für ein hochverfügbares System ist dies allerdings in den meisten Fällen schon ausreichend. In der Version 2 bringt Heartbeat einen neuen Ressourcen-Manager mit, der Cluster mit theoretisch beliebig vielen Nodes erlaubt. Die Dokumentation von Heartbeat2 spricht von getesteten Clustern mit 16 Nodes, im Internet finden sich Berichte über erfolgreich erstellte 32-Node-Cluster. Im Webumfeld sind Cluster mit mehr als zwei Nodes selten anzutreffen. Darüber hinaus ist Heartbeat2 ein zweischneidiges Schwert. Die Software selbst ist mächtig und bringt – im Gegensatz zur Version 1 – auch endlich Tools und Hilfsmittel zur Verwaltung des Clusters mit, allerdings ist die Dokumentation seit Jahren mehr als dürftig. Der mit Heartbeat2 eingeführte Ressourcen-Manager CRM wird über eine XML-Syntax konfiguriert, deren Mächtigkeit allein schon eine eigene Dokumentation erfordert, die allerdings nur in Ansätzen vorhanden ist. So wird das Einrichten eines Heartbeat2-Clusters im besten Fall zum Gedulds- und im schlimmsten Fall zum Glücksspiel. Da so ein Umstand für professionell eingesetzte Software nicht akzeptabel ist, sollten Sie für den Cluster-Betrieb bei Heartbeat in der Version 1 bleiben oder kommerzielle Varianten wie Veritas oder Symantec prüfen. Die Nodes eines Clusters kommunizieren über Netzwerk miteinander und prüfen auf diesem Weg die Status der anderen Nodes in einem Cluster. Stellt in einem 2-Node-Cluster der passive Node fest, dass der aktive Node ausgefallen ist, übernimmt er umgehend alle Ressourcen. Ressourcen können IP-Adressen und/oder Dienste sein. Bei einem Hochverfügbarkeitscluster im Hot-Standby-Modus, bestehend aus zwei Nodes, trägt der aktive Node alle Cluster-Ressourcen. Das heißt, er besitzt die virtuelle IP-Adresse, unter der die Cluster-Dienste erreicht werden können, und er besitzt auch diese Cluster-Dienste, also z. B. einen Webserver, einen Datenbankserver etc. Der passive Node übernimmt die virtuelle IP-Adresse und die Dienste, sobald der aktive Node ausfällt. In Abschnitt 6.2.2 sehen Sie, wie Sie bei Heartbeat die vom Cluster zu verwaltenden Ressourcen konfigurieren können. Ein Hochverfügbarkeitscluster besitzt als Ressource in der Regel mindestens eine virtuelle IP-Adresse. Diese ist nicht statisch an einen Node gebunden, sondern 4 http://www.linux-ha.org/
368
Der Linux-Cluster
wird dynamisch von der Cluster-Software auf dem jeweils aktiven Node eingerichtet. Darüber hinaus besitzen alle Nodes noch ihre eigenen, festen IP-Adressen. Abbildung 6.1 zeigt einen aus zwei Nodes bestehenden Cluster. Node 1 besitzt die fest im Betriebssystem konfigurierte IP-Adresse 192.168.100.100, Node 2 die IP-Adresse 192.168.100.200. In der Cluster-Software ist darüber hinaus als Cluster-IP die Adresse 192.168.100.150 gesetzt. Diese IP-Adresse ist nur auf dem aktiven Node vorhanden. Die Cluster-Dienste, beispielsweise ein Webserver, werden ausschließlich über die Cluster-IP angesprochen. Fällt ein Node aus, wechselt die Cluster-Software die Cluster-IP-Adresse auf den dann aktiven Node. Damit alle Netzwerkteilnehmer im lokalen Netz, insbesondere der nächstgelegene Switch, diese Änderung zeitnah registrieren, sendet Heartbeat nach dem Schwenk der IPAdresse ein so genanntes Gratuitous ARP. Mit diesem Paket des ARP-Protokolls fordert der Cluster alle Rechner innerhalb seiner Broadcast-Domäne dazu auf, ihren ARP-Cache für die im ARP-Paket enthaltene IP-Adresse (die Cluster-IP) zu aktualisieren. Im lokalen Netzwerk ist der Wechsel der IP-Adresse von einem Node zum anderen damit umgehend bekannt, und der Cluster-Dienst ist dadurch so gut wie unterbrechungsfrei zu erreichen. Abschnitt 6.2.3 enthält einige Messungen zu der Erreichbarkeit von Cluster-Diensten in Notfall-Situationen. 192.168.100.150
192.168.100.100
192.168.100.200
Node 1
Node 2
Abbildung 6.1
IP-Adressen eines 2-Node-Clusters
Die Kommunikation zwischen den Nodes wird im Cluster-Jargon als Heartbeat (Herzschlag) bezeichnet, wovon sich der Name des Heartbeat-Clusters ableitet. Lassen Sie sich nicht verwirren, wenn im Zusammenhang mit Clustern von Heartbeat-Paketen oder Heartbeat-Leitungen die Rede ist, in diesem Fall bezieht sich diese nicht auf die Software mit dem Namen Heartbeat, sondern auf die entsprechende Funktionalität eines Clusters. Bei der Heartbeat-Software erfolgt die Kommunikation zwischen den Nodes über UDP-Pakete. UDP weist aufgrund seiner verbindungslosen Natur eine hohe Effizienz auf. Die Heartbeat-Pakete können als Unicast zwischen den einzelnen
369
6.2
6
Hochverfügbarkeit
Nodes ausgetauscht oder als Broadcast an alle Netzwerkteilnehmer gesendet werden. Der zweite Fall ermöglicht eine Funktionalität wie Autojoin, die einem neuen Node erlaubt, sich selbständig an einem Cluster anzumelden. Aus Sicherheitsgründen kann es beim Betrieb eines Clusters sinnvoll sein, die Heartbeat-Pakete nicht über das normale Datennetz zu versenden. Abbildung 6.2 zeigt einen Datenbank-Cluster, der im Hot-Standby-Modus läuft. Die Datenbankdaten liegen auf einem Storage-System, auf das beide Nodes Zugriff haben. Lediglich auf dem aktiven Node ist der Datenbankserver gestartet, so dass sichergestellt ist, dass nur ein Datenbankprozess auf die auf dem Storage liegenden Daten zugreifen kann. Fällt der aktive Node aus, übernimmt der zweite Node die virtuelle IP-Adresse des Clusters und startet den Datenbankdienst. Aus Sicherheitsgründen werden die Heartbeat-Pakete zwischen den Nodes nicht ausschließlich über das lokale Netzwerk übertragen, sondern über eine separate, vom Netzwerk abgekoppelte Heartbeat-Leitung, die direkt und ohne weitere technische Komponenten beide Nodes verbindet. Diese dedizierte Heartbeat-Leitung kann eine Netzwerkverbindung, aber auch eine Verbindung über die serielle Schnittstelle sein. Falls Sie sich nun fragen, warum zusätzlich zu den Heartbeat-Paketen im Netzwerk noch eine separate Heartbeat-Leitung notwendig ist, stellen Sie sich das Szenario vor, das entsteht, wenn der Switch in Richtung LAN/WAN ausfällt. Damit ist keine Netzwerkkommunikation zwischen den beiden Nodes mehr möglich. Den aktiven Node wird das nicht kümmern. Der passive Node hingegen wird registrieren, dass er den aktiven Node nicht mehr erreichen kann, und annehmen, dass dieser ausgefallen ist. Die Cluster-Software kann aus naheliegenden Gründen nicht unterscheiden, ob ein Node ausgefallen oder nur der Weg zu diesem unterbrochen ist. Die Folge ist, dass der passive Node sich selbst zum aktiven Node macht und die Cluster-Ressourcen startet. Das Starten der virtuellen IP-Adresse ist dabei wenig kritisch, verheerend ist allerdings das Starten des Datenbankservers. In diesem Fall laufen auf zwei Nodes getrennte Datenbankprozesse, die auf einen gemeinsamen Datenbestand im Backend zugreifen. Bei der ersten Schreiboperation eines der beiden Nodes ist der Datenbestand inkonsistent, im schlimmsten Fall resultiert daraus eine komplette Zerstörung aller Daten. Diesen Zustand, dass sich Cluster-Knoten untereinander nicht mehr erreichen können und jeweils annehmen, dass ihr Partner ausgefallen ist, und sich dann zum aktiven Node machen, nennt man Split-Brain-Situation. Split-Brain-Situationen können ungefährlich sein, wenn daraus keine Korrumpierung von Datenbeständen resultiert. Im vorstehenden Beispiel ist eine Split-Brain-Situation für den Datenbestand der Datenbank allerdings tödlich. Aus diesem Grund gibt es in Abbildung 6.2 eine separate Heartbeat-Leitung, die direkt zwischen den beiden Nodes verläuft. Über diese Leitung können sich die Nodes auch dann noch errei-
370
Der Linux-Cluster
chen, wenn die Netzwerkverbindung ausgefallen ist. So können Sie das Risiko einer Split-Brain-Situation wesentlich verringern. Heartbeat-Leitungen über getrennte Technologien Es ist eine gute Idee, bei einer Aufteilung der Heartbeat-Leitungen auf verschiedene Strecken diese auch über unterschiedliche Anbindungen zu realisieren. Wenn Sie für die Heartbeat-Kommunikation einfach eine zweite Netzwerkverbindung verwenden, kann ein Fehler im IP-Stack oder der iptables-Konfiguration zu einem Ausfall jeglicher Netzwerkkommunikation führen. Für diesen Fall ist eine serielle Heartbeat-Leitung sinnvoll, denn dass die gesamte IP-Kommunikation und die serielle Schnittstelle eines Systems ausfallen, ist eher unwahrscheinlich.
LAN/WAN
Switch
DB 1
Heartbeat
DB 2
Switch
Storage
Abbildung 6.2 Separate Heartbeat-Leitung
371
6.2
6
Hochverfügbarkeit
Ein Wort zu Heartbeat Heartbeat ist ein tolles Programm, um einfache Cluster aufzubauen. Insbesondere 2Node-Cluster lassen sich über den herkömmlichen Betriebsmodus von Heartbeat leicht und zuverlässig erstellen. Heartbeat2 mit seinen vielfältigen neuen Funktionen und Möglichkeiten krankt an der schlechten Dokumentation, ist aber technisch auf dem richtigen Weg. Kommerzielle und »große« Clusterlösungen wie Veritas realisieren Hochverfügbarkeit und Datensicherheit über andere Techniken als eine simple Heartbeat-Leitung. In solchen Umgebungen kommen spezielle Quorum-Server oder Arbitrator zum Einsatz, die als unabhängige Instanz in einem Cluster das Auftreten von Split-Brain-Situationen überwachen und gezielt eingreifen können, wenn ein Fehlerzustand eintritt. Heartbeat in der Version 1 bietet über die Unterstützung von STONITH-Geräten die Möglichkeit, einen ausgefallenen Node auszuschalten. Aber erst mit Version 2 scheint die Unterstützung wirksamer Konzepte zur Vermeidung von Fehlerzuständen im Cluster Einzug in die Entwicklung von Heartbeat gehalten zu haben.
6.2.2
Installation und Konfiguration
Sowohl für Ubuntu als auch für Gentoo sind Heartbeat-Pakete über den distributionseigenen Paketmanager verfügbar. Ubuntu ist Gentoo bei der Versionierung voraus, zum Zeitpunkt der Manuskripterstellung war die aktuelle Version unter Ubuntu 2.1.3-2 und unter Gentoo 2.0.7-r2. Dass unter Gentoo wieder ein Release-Candidate verwendet wird, spricht nicht für die Pflege der Distribution. An dieser Stelle gilt das bereits in Kapitel 4, »Serverdienste«, zum ProFTPD Gesagte: Das Verwenden von Beta-Versionen und Release-Candidates sollte für eine professionell genutzte Distribution tabu sein. Unter Ubuntu können Sie Heartbeat über die folgenden Pakete installieren: # sudo apt-get install heartbeat-2
Unter Gentoo mit … # sudo emerge heartbeat
Dieser Abschnitt beschreibt die Verwendung von Heartbeat im Version-1-Modus. Damit können Sie unter Einsatz herkömmlicher Konfigurationssyntax einen 2-Node-Cluster aufbauen. Wenn Ihr Cluster nicht mehr als zwei Nodes enthalten soll, ist dieser Modus die richtige Wahl, denn die XML-Konfiguration von Heartbeat2 ist alles andere als intuitiv. Absatz 0 beschreibt die Konfiguration eines Heartbeat-2-Clusters. Die Konfiguration von Heartbeat ist unter Ubuntu und Gentoo identisch, so dass im Folgenden keine Unterscheidung zwischen den beiden Distributionen notwendig ist. Die weiter unten beschriebene Beispielinstallation eines 2-Node-Clusters besteht aus den folgenden Parametern:
372
Der Linux-Cluster
System
IP
Bedeutung
Hardy
192.168.0.20
Master
Gentoo
192.168.0.114
Slave
Ha
192.168.0.25
virtuelle IP-Adresse
Für den Betrieb im Version-1-Modus benötigt Heartbeat drei Dateien: 왘
/etc/ha.d/ha.cf:
왘
/etc/ha.d/haresources: enthält die vom Cluster gesteuerten Ressourcen
왘
/etc/ha.d/authkeys:
die Konfigurationsdatei von Heartbeat Authentifizierungsparameter für die Kommunikation der Cluster-Nodes untereinander
Grundsätzlich sind die Konfigurationsdateien auf beiden Cluster-Nodes identisch. Die Datei /etc/ha.d/ha.cf enthält Direktiven zum Verhalten des Clusters. Die folgende Konfiguration legt zunächst die Log-Facility der Cluster-Meldungen für den Syslog-Server fest: logfacility local0
Durch Verwenden des Syslog-Servers entfällt das manuelle Verwalten von Logdateien des Clusters. Bedenken Sie aber, dass die Logaufrufe blockierend sind. Bei großem Logaufkommen kann das zu einer starken Belastung des Systems führen. In diesem Fall ist das Verwenden eigener Logdateien für Heartbeat sinnvoll. Die nächste Direktive bestimmt die Netzwerkschnittstelle, über welche die Heartbeat-Broadcasts gesendet und empfangen werden. bcast eth0
Falls Sie aus Gründen der Netzwerkhygiene statt Broadcasts lieber Unicasts verwenden möchten, lautet die Direktive ucast, gefolgt vom Namen der Netzwerkschnittstelle und der IP-Adresse des jeweils anderen Nodes, also z. B. ucast eth0 192.168.0.114. In diesem Fall sind die Direktiven auf beiden Nodes unterschiedlich, da Sie den jeweils anderen Node angeben müssen. Heartbeat und Firewalls Heartbeat versendet seine Heartbeat-Pakete an den UDP-Port 694. Wenn Sie Ihre Systeme mit Host-Firewalls schützen, müssen Sie sicherstellen, dass die Nodes untereinander auf diesem Port kommunizieren dürfen: iptables -A INPUT -p udp -s X -d Y --dport 694 -i eth0 -j ACCEPT iptables -A OUTPUT -p udp -s X -d Y --dport 694 -i eth0 -j ACCEPT
Der Wert X steht dabei für die IP-Adresse des entfernten Cluster-Nodes, Y für die eigene IP-Adresse des jeweiligen Systems.
373
6.2
6
Hochverfügbarkeit
Die Namen der beiden Cluster-Nodes geben Sie über die Direktive node an. Die Namen müssen entweder über DNS oder /etc/hosts bekannt sein. Alternativ können Sie hier auch die IP-Adressen der Nodes verwenden. node hardy node gentoo
Um die Funktionalität des Netzwerkes überprüfen zu können, kann Heartbeat die Erreichbarkeit so genannter Ping-Devices über ICMP-Anfragen prüfen. Ein sinnvolles Ping-Device wäre beispielsweise das Gateway des lokalen Netzwerkes. Ist ein Ping-Device von einem Node aus nicht erreichbar, antwortet also nicht auf ICMP Echo Requests, testet Heartbeat die Verbindung zu diesem Ping-Device über den anderen Node und kann dadurch Rückschlüsse auf den Zustand des Netzwerkes ziehen. Versprechen Sie sich allerdings nicht zu viel Intelligenz von dieser Funktion. Gegen Split-Brain-Zustände und andere Unwägbarkeiten hilft nur ein sorgfältig durchdachtes Konzept. ping 192.168.0.1
Über die Direktive keepalive können Sie das Intervall bestimmen, in dem der Node die Heartbeat-Pakete versendet. Je kleiner das Intervall, desto schneller kann ein Node den Ausfall eines anderen Nodes erkennen. Allerdings steigt mit einem kleinen Intervall auch der Netzwerkverkehr merklich. Wenn Sie Heartbeat-Pakete über UDP-Broadcasts versenden lassen, sollten Sie das Intervall nicht kleiner als zwei Sekunden setzen. Bei der Verwendung von UDP-Unicasts sind auch Werte im Millisekundenbereich möglich, und unter Umständen auch sinnvoll (keepalive 500ms). Ein konservativer Wert sind zwei Sekunden: keepalive 2
Bleibt ein Heartbeat-Paket aus, wird der Node, der dieses Ausbleiben registriert, reagieren. Wie schnell er reagiert, können Sie mit der Direktive warntime festlegen. Beim Erreichen der warntime gibt Heartbeat eine Warnung aus, übernimmt aber noch keine Cluster-Ressourcen: WARN: Late heartbeat: Node gentoo: interval 20510 ms
Das wiederholte Auftreten dieser Warnungen deutet auf Probleme hin, denen man nachgehen sollte. warntime 10
Neben der warntime, die – ihrem Namen entsprechend – den Zeitraum spezifiziert, nach dem Heartbeat eine Warnung über das Ausbleiben der Heartbeat-Pakete des oder der anderen Nodes ausgibt, ist die Direktive deadtime die wichtigste Direktive für den Clusterbetrieb. Mit dieser Direktive legen Sie die Zeit fest, nach der ein Node als nicht mehr aktiv (»tot«) erkannt bzw. markiert wird und
374
Der Linux-Cluster
der diesen Zustand feststellende Node die Cluster-Ressourcen übernimmt. Dieser Wert muss mit Sorgfalt gewählt und gründlich getestet werden, denn ein zu niedriger Wert kann dazu führen, dass Nodes fälschlicherweise als tot erkannt werden, obwohl sie das gar nicht sind. Ein zu hoher Wert hingegen kann bewirken, dass der Ausfall eines Nodes zu lange unerkannt bleibt und der Cluster-Dienst für den entsprechenden Zeitraum nicht erreichbar ist. deadtime 30
Die Last mit der Last Das Antwortverhalten eines Systems verändert sich in Abhängigkeit von der Last, unter der das System steht. Mit zunehmender Last erhöht sich die Antwortzeit, und das gilt auch für die Heartbeat-Software. Bedenken Sie diesen Umstand beim Festlegen der verschiedenen Timeouts. Wenn ein Node wegen zu hoher Last nicht schnell genug seine Heartbeat-Pakete versenden kann, führen zu niedrig eingestellte warntime- und deadtime-Werte schnell zu unerwünschten Ergebnissen. Ebenso kann eine hohe Netzwerklast dazu führen, dass die Heartbeat-Pakete nicht rechtzeitig eintreffen. Gehen Sie bei der Konfiguration der kritischen Direktiven daher vorsichtig vor, und halten Sie die Betriebsumgebung (System- und Netzwerklast) gut im Auge. Dabei helfen Ihnen Tools wie MRTG und Nagios.
Nach dem Start der Cluster-Software, die in der Regal automatisch beim Systemstart geladen wird, sollte diese eine Zeitlang mit dem Bewerten von HeartbeatPaketen der anderen Nodes warten, denn jedes System benötigt nach einem Systemstart eine gewisse Zeit, bis alle Ressourcen gestartet sind – insbesondere auf Servern, die viele verschiedene Dienste anbieten (z. B. ein LAMP-System). Mit der Direktive initdead können Sie einen Zeitraum nach dem Start der HeartbeatSoftware festlegen, innerhalb dessen der Cluster noch keine Statusmeldungen der anderen Nodes auswertet und inaktiv bleibt. An dieser Stelle können Sie einen hohen Wert setzen, denn ob ein System ein oder zwei Minuten braucht, bis es nach einem Systemstart erreichbar ist, spielt in der Regel kaum eine Rolle. initdead 120
Um die durch den Cluster verursachte Netzwerklast gering zu halten, kann Heartbeat Nachrichten komprimieren. Über die folgende Direktive geben Sie eine Größe in Kilobyte an, ab der Heartbeat Nachrichten komprimiert. compression_threshold 2
Damit die vorstehende Direktive wirksam wird, müssen Sie mit der compressionDirektive einen Kompressionsalgorithmus festlegen. Mögliche Werte sind von den auf dem jeweiligen System installierten Kompressionsbibliotheken abhängig. compression bz2
375
6.2
6
Hochverfügbarkeit
Die beschriebenen Direktiven der Datei /etc/ha.d/ha.cf regeln das allgemeine Verhalten des Clusters, machen aber keine Aussage darüber, welcher Node der Master-Node ist und welche Ressourcen der Cluster verwalten soll. Dies ist in der Datei /etc/ha.d/haresources festgelegt: hardy
192.168.0.25
apache2
Der erste Eintrag legt den Master-Node des Clusters fest. Mögliche Werte sind die über die node-Direktive in der Datei /etc/ha.d/ha.cf definierten Nodes. Die folgenden Einträge stehen für die Ressourcen, die der Cluster verwaltet und an den jeweils aktiven Node bindet. In diesem Fall ist das die IP-Adresse 192.168.0.25 und der Dienst apache2. Weitere Dienste können Sie nach Belieben hinzufügen. Wichtig ist, dass der angegebene Name einem Init-Skript im Verzeichnis /etc/ init.d entspricht, das die Parameter start und stop akzeptiert. Über diesen Mechanismus steuert Heartbeat die Dienste. Vorsicht mit dem automatischen Start Ein Dienst, der vom Cluster verwaltet wird – wie im vorliegenden Beispiel apache2 – darf nicht automatisch beim Systemstart über Init-Skripte gestartet werden. Der Cluster übernimmt das Starten und Stoppen des Dienstes. Entfernen Sie daher für alle Dienste, die der Cluster steuert, die entsprechenden Init-Links. Unter Ubuntu: # update-rc.d -f apache2 remove Removing any system startup links for /etc/init.d/apache2 ... /etc/rc0.d/K09apache2 /etc/rc1.d/K09apache2 /etc/rc2.d/S91apache2 /etc/rc3.d/S91apache2 /etc/rc4.d/S91apache2 /etc/rc5.d/S91apache2 /etc/rc6.d/K09apache2
Und unter Gentoo: # rc-update -d apache2 * 'apache2' removed from the following runlevels: default
Die letzte Datei, die Sie für den Betrieb von Heartbeat einrichten müssen, ist /etc/ ha.d/authkeys. Darin sind die Authentifizierungsmethode und das Kennwort abgelegt, das alle Cluster-Nodes kennen müssen, um miteinander kommunizieren zu können. Der Inhalt dieser Datei muss auf allen Nodes eines Clusters zwingend gleich sein, da die Nodes ansonsten die Heartbeat-Pakete des oder der anderen Nodes nicht akzeptieren und der Cluster nicht funktioniert. auth 1 1 md5 foobar
376
Der Linux-Cluster
Die erste Zeile gibt an, welcher Schlüssel für die Ver- und Entschlüsselung der Daten verwendet wird. In diesem Fall gibt es nur einen Schlüssel, und dieser ist in der zweiten Zeile angegeben. Das Hash-Verfahren, mit dem der Schlüssel reduziert wird, ist in diesem Fall MD5. Zur Auswahl steht noch SHA1 und die Checksummenprüfung CRC. Während CRC keinerlei Sicherheit bietet, sind MD5 und SHA1 zumindest Hash-Algorithmen, die einen gewissen Schutz vor dem Entschlüsseln des Passwortes bieten. Wirkliche Sicherheit ist damit allerdings nicht gegeben, da Heartbeat die Hash-Werte offenbar ohne Salz erstellt, womit der Einsatz von Rainbow-Tables zum Entschlüsseln des Passwortes aus den Heartbeat-Paketen möglich wäre. Vorsicht Falle Nach dem Anlegen der Konfigurationsdateien wird Heartbeat – in Abhängigkeit von der Umask des Systems – beim Start falsche Rechte auf der Datei /etc/ha.d/authkeys bemängeln: ERROR: Bad permissions on keyfile [/etc/ha.d/authkeys], 600 recommended
Machen Sie nicht den Fehler, mit einem beherzten und gut gemeinten chmod 600 /etc/ ha.d/* alle Dateien in dem Verzeichnis auf 600 zu setzen. Die Datei /etc/ha.d/harc ist ein Shellskript und muss für den Benutzer root ausführbar sein! Heartbeat verwendet dieses Skript, um die vom Cluster gesteuerten Dienste zu starten und anzuhalten. Falsche Rechte auf dem Skript führen dazu, dass Heartbeat diese Arbeit nicht mehr ausführen kann – der Cluster ist zwar grundsätzlich funktionsfähig, Dienste kann er aber nicht bedienen.
6.2.3
Szenarien
Nach dem Start des Heartbeat-Dienstes auf den beiden Cluster-Nodes können Sie im Syslog die Aktivitäten des Clusters beobachten: # sudo tail –f /var/log/messages
Der aktive Node, in diesem Fall hardy, übernimmt nach dem Start die in der Datei /etc/ha.d/haresources festgelegten Ressourcen: [...] info: Acquiring resource group: hardy 192.168.0.25 apache2 [...] INFO: Using calculated nic for 192.168.0.25: eth0 INFO: Using calculated netmask for 192.168.0.25: 255.255.255.0 INFO: eval ifconfig eth0:0 192.168.0.25 netmask 255.255.255.0 broadcast 192.168.0.255 INFO: Success [...]
377
6.2
6
Hochverfügbarkeit
info: Running /etc/init.d/apache2 [...]
start
Sobald sich der passive Node am Cluster anmeldet, registriert das der aktive Node: [...] info: Link gentoo:eth0 up. info: Status update for node gentoo: status init info: Status update for node gentoo: status up [...]
Mit einem Netzwerksniffer wie Wireshark oder tcpdump können Sie die Heartbeat-Pakete im Netzwerk betrachten (Abbildung 6.3).
Abbildung 6.3 UDP-Broadcasts der Cluster-Nodes
Die virtuelle IP-Adresse des Clusters ist erreichbar, ebenso der Apache-Webserver auf dem aktiven Node.
378
Der Linux-Cluster
# ping 192.168.0.25 PING 192.168.0.25 (192.168.0.25): 56 data bytes 64 bytes from 192.168.0.25: icmp_seq=0 ttl=64 time=109 ms 64 bytes from 192.168.0.25: icmp_seq=1 ttl=64 time=0 ms 64 bytes from 192.168.0.25: icmp_seq=2 ttl=64 time=0 ms 64 bytes from 192.168.0.25: icmp_seq=3 ttl=64 time=0 ms 64 bytes from 192.168.0.25: icmp_seq=4 ttl=64 time=0 ms ----192.168.0.25 PING Statistics---5 packets transmitted, 5 packets received, 0.0 % packet loss round-trip (ms) min/avg/max/med = 0/22/109/0
Um festzustellen, auf welchem Host der Apache-Webserver läuft, können Sie ein kleines PHP-Skript verwenden: $out = shell_exec('uname -a'); echo "$out"; ?>
Dieses Skript ruft über die PHP-Funktion shell_exec den Befehl uname –a auf Systemebene auf und gibt das Ergebnis an den Browser aus. So erhalten Sie den Namen des Systems, auf dem das Skript ausgeführt wurde. Solange hardy der aktive Node ist, wird die Ausgabe wie in Abbildung 6.4 aussehen.
Abbildung 6.4 »hardy« ist der aktive Cluster-Node.
Fällt der aktive Node aus, z. B. durch Anhalten des Heartbeat-Dienstes, registriert der passive Node dies umgehend: [...] info: Received shutdown notice from 'hardy'. info: Resources being acquired from hardy. info: acquire all HA resources (standby). [...]
Der Node übernimmt die IP-Adresse und sendet ein Gratuitous ARP, um alle Systeme im lokalen Netzwerk über die Änderung zu unterrichten: [...] INFO: Sending Gratuitous Arp for 192.168.0.25 on eth0:0 [eth0]
Anschließend startet der Node den Apache: [...] info: Acquiring resource group: hardy 192.168.0.25 apache2 info: Running /etc/init.d/apache2 start [...]
Das Ergebnis lässt sich über das obengezeigte PHP-Skript ermitteln (Abbildung 6.5).
Abbildung 6.5 »gentoo« ist jetzt der aktive Node.
Durch das aktive Herunterfahren des Heartbeat-Dienstes auf dem Master-Node hat dieser den Slave-Node darüber informiert, dass er die Ressourcen übernehmen soll. Dadurch konnte der Slave umgehend reagieren, so dass der Schwenk der Dienste vom Node hardy zum Node gentoo unbemerkt vonstattengehen konnte. Ein durchgängiges Ping auf die virtuelle IP-Adresse 192.168.0.25 zeigt während des Schwenkvorgangs keine Unterbrechung der Erreichbarkeit: [...] 64 bytes 64 bytes 64 bytes 64 bytes 64 bytes 64 bytes 64 bytes 64 bytes 64 bytes 64 bytes 64 bytes 64 bytes 64 bytes [...]
380
from from from from from from from from from from from from from
Automatisches Zurückschwenken Heartbeat unterstützt das automatische Failback, also das Zurückschwenken auf den als Master-Node konfigurierten Node, sobald dieser wieder erreichbar ist. Dieses Verhalten können Sie über die Direktive auto_failback on in der Datei /etc/ha.d/ha.cf aktivieren. Vordergründig scheint dieses Verhalten praktisch und wünschenswert zu sein, ich möchte allerdings aus eigener Erfahrung davon abraten. Wenn ein Cluster in einen Zustand gerät, dass er zu einem anderen Node schwenkt, liegt normalerweise ein Problem vor. Das kann eine triviale Angelegenheit sein, wie z. B. eine kurzzeitige Lastspitze im Netzwerk, es kann aber auch ein schwerwiegendes Problem sein, wie beispielsweise ein Softwarefehler o. Ä. In jedem Fall sollte ein Schwenk unbedingt eine manuelle Prüfung der Situation durch einen Administrator nach sich ziehen, damit dieser die Ursache des Schwenks ermitteln und gegebenenfalls beseitigen kann. Überwachen Sie den ClusterStatus mit Nagios, und Sie sind immer auf dem Laufenden, falls etwas passiert.
Anders sieht es mit der Verfügbarkeit aus, wenn der aktive Cluster-Node unvermittelt seinen Betrieb einstellt. Simulieren lässt sich das einfach durch Ziehen des Netzwerkkabels oder – beim Einsatz als virtuelle Maschine – durch Deaktivieren der Netzwerkverbindungen. Der Slave-Node erkennt nach dem über die Direktive deadtime festgelegten Zeitraum den Ausfall des Masters und übernimmt die Ressourcen des Clusters. Dies lässt sich im Selbstversuch prüfen. Auf dem MasterNode ziehen Sie das Netzwerkkabel oder deaktivieren das Netzwerk (Letzteres bitte nur, wenn Sie physischen Zugriff auf die Maschine haben!). # date Sa 20. Sep 11:10:26 CEST 2008 # sudo ifconfig eth0 down
Der Slave-Node (gentoo) erkennt nach den in der Konfiguration als deadtime festgelegten 30 Sekunden den Master als ausgefallen und übernimmt: Sep 20 11:09:09 gentoo heartbeat: [19551]: WARN: node hardy: is dead [...] info: mach_down takeover complete for node hardy.
Die vom Cluster verwalteten Ressourcen sind also für den Zeitraum von 30 Sekunden nicht erreichbar gewesen. Ob dies eine akzeptable Zeitspanne ist, hängt vom Einsatzzweck des Servers ab. Denken Sie beim Feintuning aber daran, die Zeiten nicht so knapp zu bemessen, dass der Cluster durch (kurzfristige) Lastspitzen zu Fehlentscheidungen bewogen wird. Heartbeat und Xen Falls Ihnen beim Lesen des Abschnitts über den Heartbeat-Cluster der Gedanke gekommen ist, verschiedene Xen-Hosts in einem Cluster zusammenzufassen – das funktioniert problemlos. Sie können auf diese Weise ohne zusätzlichen Aufwand an Hardware einen Cluster aufbauen und testen.
381
6.2
6
Hochverfügbarkeit
6.3
Verteilte Datenhaltung
Zur Herstellung von Hochverfügbarkeit ist ein Cluster nur die halbe Miete. Damit können Sie zwar sehr einfach Dienste hochverfügbar einrichten, mit der Hochverfügbarkeit von Daten sieht es aber etwas schwieriger aus. Das Betriebssystem und alle für den Betrieb der Cluster-Nodes notwendigen Programme sind lokal auf dem jeweiligen Node installiert und werden über den lokalen Paketmanager verwaltet und gewartet. Die beweglichen Daten, also z. B. die Daten Ihrer Website, E-Mails, Benutzerdaten etc., können nicht gleichzeitig auf beiden ClusterNodes liegen, es sei denn, Sie richten einen Synchronisationsmechanismus für diese Daten ein. Das kann in der simplen Ausgabe ein einfaches rsync-Skript5 sein, das auf Applikationsebene zyklisch Daten vom aktiven Node auf den passiven Node transferiert. Bei zunehmender Datenmenge stoßen Sie dabei aber schnell an die Grenzen einer Lösung im Eigenbau auf Applikationsebene. Allein durch den Kommunikations-Overhead ist eine solche Lösung wenig praktikabel. rsync, ein Protokoll der Anwendungsebene, kommuniziert seinerseits über SSH, ein weiteres Protokoll der Anwendungsebene, das wiederum auf TCP aufsetzt. Hinzu kommt, dass sich mit rsync keine kontinuierliche Synchronisation einrichten lässt, die jede Änderung auf einem Node umgehend auf den anderen Node transferiert. Sie können rsync nur in festen Zeitabständen aufrufen. Sind die Zeitabstände zu groß, dauert es unter Umständen zu lange, bis die Nodes synchronisiert sind. Ein Ausfall zwischen zwei Synchronisierungsintervallen kann dann möglicherweise fatale Folgen haben. Sind die Abstände zwischen zwei rsync-Aufrufen zu kurz, haben Sie entweder in kürzester Zeit einen Rechner voller sich gegenseitig ausbremsender rsync-Prozesse oder – wenn Sie das rsync-Skript hinreichend intelligent gestaltet haben, so dass ein neuer Prozess nur gestartet wird, wenn kein alter Prozess mehr vorhanden ist – die Abstände zwischen zwei Synchronisierungen werden automatisch immer größer, abhängig von der zu synchronisierenden Datenmenge. Eine Lösung kann die Nutzung eines zentralen Storages sein, entweder in Form eines SAN- oder eines NAS-Storage. Ein SAN (Storage Area Network) ist ein Netzwerkspeicher, der in der Regel über Fiber Channel oder iSCSI von den angeschlossenen Systemen angesprochen wird und in diesen Systemen als zusätzliches Blockdevice verwaltet wird. Auf SAN-Basis lassen sich sehr performante Speicherlösungen realisieren, die allerdings einen hohen finanziellen Aufwand bei der Einrichtung erfordern, nicht zuletzt für die Infrastruktur bei der Verwendung von Fibre Channel.
5 http://samba.anu.edu.au/rsync/
382
Verteilte Datenhaltung
Einen ähnlichen Ansatz bietet ein NAS-Storage (Network Attached Storage). Darunter versteht man ebenfalls einen zentralen Netzwerkspeicher, der im Gegensatz zum SAN allerdings nicht über blockbasierte Protokolle, sondern auf Applikationsebene angesprochen wird, also z. B. per NFS, SMB oder CIFS. Dadurch ist der Konfigurationsaufwand wesentlich geringer als bei einem SAN. Es entfällt nicht nur die eigene FC-Infrastruktur, sondern auch das mitunter aufwendige Einbinden der SAN-LUNs in die Systeme. Der Netzwerkspeicher, der so genannte NAS-Filer, gibt seine Speicherbereiche über die jeweiligen Protokolle frei, und die Systeme im Netz können diese Freigaben mounten. Im Gegensatz zum SAN ist ein NAS wesentlich weniger performant, da allein aufgrund der Anwendungsprotokolle ein viel höherer Kommunikations-Overhead entsteht. Beide Lösungen, SAN sowie NAS, stellen zwar zentral Speicher für verschiedene Systeme bereit, lösen das Problem der zentralen Datenhaltung für einen Cluster aber nicht. Um Inkonsistenzen im Datenbestand zu vermeiden, muss sichergestellt sein, dass immer nur der aktive Node eines Clusters auf den Datenbestand zugreifen darf. Dies zu regeln ist aber keine Aufgabe des Storages, sondern der zugreifenden Systeme. Es muss daher eine andere Lösung her. Diese steht unter Linux in Form des Distributed Replicated Block Device (DRBD) zur Verfügung.
6.3.1
DRBD
DRBD ist ein Kernel-Treiber, der eine RAID-1-Funktionalität für zwei Hosts im Netzwerk bietet. DRBD stellt dazu auf jedem Host ein Blockdevice zur Verfügung (daher auch die Konzeption als Kernel-Treiber). Das aktive System kann das Blockdevice ganz normal verwenden. Alle Änderungen auf diesem Blockdevice werden umgehend über das Netzwerk auf das beim passiven System vorhandene Blockdevice gespiegelt. Dabei ist die Performance des verwendeten Netzwerkes von entscheidender Bedeutung für die Gesamtperformance beider Systeme, denn je nach Betriebsart kann ein Schreibzugriff auf das DRBD-Blockdevice so lange blockieren, bis der dazugehörige Schreibzugriff auf dem gespiegelten Blockdevice ausgeführt worden ist. Bei großen Datenmengen und einem langsamen Netzwerk kann dies zu merklichen Verzögerungen führen. Idealerweise sollte die DRBDKommunikation über eine eigene Netzwerkverbindung geführt werden, analog zur separaten Leitung bei Heartbeat. DRBD erscheint dem Betriebssystem gegenüber als Blockdevice, daher kann es mit beliebigen Dateisystemen und Dateisystem-Managern wie z. B. LVM genutzt werden.
383
6.3
6
Hochverfügbarkeit
6.3.2
Installation
Unter Ubuntu können Sie DRBD mit dem folgenden Befehl installieren: # sudo apt-get install drbd8-utils
Nach Abschluss der Installation sollten die benötigten Programme installiert und das Modul drbd geladen sein: # lsmod |grep drbd drbd cn
213000 9632
0 1 drbd
Unter Gentoo befindet sich DRBD im Paket drbd-kernel. Damit die Installation erfolgreich ist, muss der Kernel mit den folgenden beiden Optionen übersetzt sein, da sich ansonsten das Kernel-Modul von DRBD nicht erstellen lässt: kernelspace linker Cryptographic algorithm manager
Über genkernel (zu installieren mit emerge genkernel) können Sie den Kernel bei Bedarf anpassen. Wenn Sie die Kernel-Konfiguration mit menuconfig (genkernel --menuconfig) aufrufen, finden Sie die erste Option im Abschnitt Device Drivers (Abbildung 6.6).
Abbildung 6.6
Abschnitt »Device Drivers« in der Kernel-Konfiguration
Die zweite Option befindet sich im Abschnitt Cryptographic API ().
384
Verteilte Datenhaltung
Abbildung 6.7 Abschnitt »Cryptographic API« in der Kernel-Konfiguration
Anschließend können Sie den Kernel mit … # sudo emerge drbd-kernel
… installieren. Voraussetzung für die Verwendung von DRBD ist darüber hinaus noch eine freie Partition auf beiden Nodes. Diese muss zum Zeitpunkt der Installation nicht besonders eingerichtet sein, das geschieht erst mit der Konfiguration von DRBD.
6.3.3
Konfiguration
Vor der Inbetriebnahme von DRBD müssen Sie für diesen eine Partition anlegen. Im folgenden Beispiel ist dies /dev/sdb1. Die Konfiguration von DRBD liegt in der Datei /etc/drbd.conf, sowohl unter Ubuntu als auch unter Gentoo. Sie ist in verschiedene Abschnitte aufgeteilt, von denen jeder mit einem Schlüsselwort beginnt und im Anschluss an dieses in geschweifte Klammern gekapselt ist. Der Abschnitt global legt verschiedene global gültige Parameter fest und muss vor allen anderen Abschnitten in der Konfigurationsdatei stehen. Der Abschnitt common erlaubt das Festlegen von Direktiven, die in allen ressource-Abschnitten gültig sein sollen. Die ressource-Abschnitte wiederum dienen zur Konfiguration der DRBD-Nodes. Die wichtigste Direktive im global-Abschnitt ist die folgende: usage-count no;
385
6.3
6
Hochverfügbarkeit
Damit untersagen Sie der DRBD-Software, Nutzungsstatistiken an den Server des DRBD-Projektes zu schicken. Diese Statistiken sind auf der Webseite http:// usage.drbd.org/ öffentlich verfügbar (Abbildung 6.8). Die Motivation hinter dieser Datensammlung wird auf der Website erklärt: »As a response to your data, the server will tell you how many users before you have installed this version. With a high counter the DRBD developers have a high motivation to continue development of the software.« Ob für eine Erhebung über die Nutzung einer Software, die für die Verarbeitung mitunter sensibler und personenbezogener Daten entwickelt wurde, Nutzungsdaten von den eigenen Systemen an den Server des Softwareherstellers geschickt werden müssen – egal ob sich dahinter eine Firma oder ein Open-Source-Projekt verbirgt –, ist schon recht zweifelhaft. Es steckt nicht hinter jeder Statistik eine Bespitzelung, aber das Sammeln von Daten führt in vielen Fällen irgendwann zum Missbrauch dieser Daten, weswegen man sich jeder Möglichkeit entziehen sollte, persönliche Daten – auch in anonymisierter Form – preiszugeben.
Abbildung 6.8 DRBD-Nutzungsstatistiken auf http://usage.drbd.org
386
Verteilte Datenhaltung
Die gesamte Konfiguration für ein einfaches Setup zur Spiegelung der Partition /dev/sdb1 auf den Hosts hardy und hardy2 ist die folgende: global { usage-count no; } common { syncer { rate 10M; } } resource data { protocol C; handlers { pri-on-incon-degr "echo o > /proc/sysrq-trigger ; halt -f"; pri-lost-after-sb "echo o > /proc/sysrq-trigger ; halt -f"; local-io-error "echo o > /proc/sysrq-trigger ; halt -f"; } startup { } disk { on-io-error detach; } net { after-sb-0pri disconnect; after-sb-1pri disconnect; after-sb-2pri disconnect; rr-conflict disconnect; } syncer { rate 10M; al-extents 257; } on hardy { device /dev/drbd0; disk /dev/sdb1; address 192.168.0.20:7788; meta-disk internal; } on hardy2 { device disk address meta-disk }
Neben den verschiedenen Error-Handlern und Direktiven zum Tuning der Replizierung, die nur in Ausnahmefällen – wie z. B. sehr großen zu spiegelnden Datenmengen, einer langsamen Netzwerkverbindung oder Lastproblemen der beteiligten Nodes – modifiziert werden müssen und die in der mit DRBD ausgelieferten Beispielkonfiguration dokumentiert sind, ist die Direktive protocol von sehr großer Bedeutung für Verhalten und Performance des DRBD-Verbundes. Damit legen Sie einen von drei möglichen Replizierungsmodi A, B oder C für DRBD fest: 왘
Modus A: Sobald eine Schreiboperation auf dem Master-Node abgeschlossen und vom DRBD-Modul zur Replikation an den TCP-Stack des Betriebssystems geschickt worden ist, gilt die Schreiboperation als komplett ausgeführt. Dieser Modus ist der schnellste, birgt aber die Gefahr eines Datenverlustews, wenn der Master nach dem lokalen Schreibvorgang, aber vor dem Senden über das Netzwerk ausfällt.
왘
Modus B: Eine Schreiboperation gilt als abgeschlossen, sobald sie auf dem Master lokal geschrieben und vom DRBD-Modul des Slaves per Netzwerk entgegengenommen worden ist. Ein Datenverlust ist auch hier möglich, wenngleich weniger wahrscheinlich als beim Modus A.
왘
Modus C: Die sicherste, aber auch langsamste Variante. Eine Schreiboperation ist erst dann abgeschlossen, wenn sie auf beiden Systemen auf die Festplatte geschrieben worden ist. Der Ausfall eines der beiden Nodes kann daher nicht zu Datenverlusten oder -inkonsistenzen führen.
Im Zweifelsfall sollten Sie grundsätzlich den Modus C wählen, da nur dieser sinnvoll vor Problemen schützt. Alle anderen Modi ergeben in einem produktiven Umfeld wenig Sinn und laufen dem eigentlich Einsatzzweck von DRBD, nämlich die Datensicherheit zu erhöhen, zuwider. Die eigentliche, individuelle Konfiguration findet mit den beiden on-Direktiven statt: on hardy { device disk address meta-disk } on hardy2 { device disk address meta-disk }
Damit legen Sie die beiden Nodes fest, über die Sie die DRBD-Partition spiegeln möchten. Das Device /dev/drbd0 bestimmt dabei das Blockdevice, unter dem das DRBD-Modul den Zugriff auf die Partition erlaubt. Die zu verwendende Partition wird mit dem Schlüsselwort disk definiert. Die Werte müssen nicht auf beiden Hosts gleich sein. Den jeweiligen Socket legen Sie mit der Direktive address fest, und sofern Sie eine interne Festplatte als Datenträger verwenden, muss die Direktive meta-disk den Wert internal haben. Interessant ist noch die Direktive degr-wfc-timeout, denn sie legt die Zeit fest, die ein Node auf seinen Partner wartet, wenn dieser Node vor dem Reboot bereits kein funktionierender DRBD-Verbund mehr war. Der Standardwert ist 120 Sekunden. Wird ein Node gestartet, ohne dass er seinen Partner erreichen kann, wartet er 120 Sekunden auf diesen. Das kann in Fällen, in denen der Partner irreparabel beschädigt ist, störend sein. Für den Fall, dass der DRBD-Verbund vor dem Reboot noch intakt war, ein Node nach dem Reboot seinen Partner aber nicht mehr finden kann, wartet er die mit der Direktive wfc-timeout definierte Zeitspanne. Der Standardwert ist 0, was bedeutet, dass der DRBD-Node unendlich lange wartet – das System startet nicht. Dieses Verhalten ist grundsätzlich erwünscht, um Split-Brain-Situationen durch Netzwerkfehler zu vermeiden. Wenn ein Node aber längerfristig ausgefallen ist, sollten Sie den Wert der Direktive ändern, allerdings nur so lange, bis beide Nodes wieder verfügbar sind. Nach dem Starten von DRBD definieren Sie mit dem Programm drbdadm den Master-Node, den so genannten Primary: # sudo drbdadm -- -o primary data
Wenn Sie für DRBD eine neue Partition anlegen möchten, verwenden Sie den Befehl fdisk gefolgt vom Namen der zu partitionierenden Festplatte. Über das Tastenkürzel (n) können Sie eine neue Partition erzeugen, über (w) die Änderung auf die Festplatte schreiben und mit fdisk verlassen. Mit der Taste (m) erhalten Sie eine Übersicht über die möglichen Optionen von fdisk. # fdisk /dev/sdb Command (m for help): p Disk /dev/sdb: 2147 MB, 2147483648 bytes 255 heads, 63 sectors/track, 261 cylinders Units = cylinders of 16065 * 512 = 8225280 bytes Disk identifier: 0xea17ca8a Device Boot Start End Blocks Id Command (m for help): n Command action
System
389
6.3
6
Hochverfügbarkeit
e p
extended primary partition (1-4)
p Partition number (1-4): 1 First cylinder (1-261, default 1): Using default value 1 Last cylinder or +size or +sizeM or +sizeK (1-261, default 261): Using default value 261 Command (m for help): w The partition table has been altered! Calling ioctl() to re-read partition table. Syncing disks.
Die betreffende Partition müssen Sie auf beiden Hosts einrichten. Anschließend können Sie DRBD auf beiden Nodes starten. # sudo /etc/init.d/drbd start
Ob das Modul korrekt geladen worden ist, können Sie mit lsmod kontrollieren: # lsmod |grep drbd drbd 213000 cn 9632
3 1 drbd
Daneben muss es auch noch das in der Konfigurationsdatei definierte Blockdevice geben: # ls -la /dev/drbd0 brw-rw----+ 1 root disk 147, 0 2008-09-25 22:10 /dev/drbd0
Auf dem Primary können Sie nun ein Dateisystem auf dem DRBD-Blockdevice erzeugen: # sudo mkfs.ext3 /dev/drbd0 mke2fs 1.40.8 (13-Mar-2008) Filesystem label= OS type: Linux Block size=4096 (log=2) Fragment size=4096 (log=2) 131072 inodes, 524087 blocks 26204 blocks (5.00 %) reserved for the super user First data block=0 Maximum filesystem blocks=536870912 16 block groups 32768 blocks per group, 32768 fragments per group 8192 inodes per group Superblock backups stored on blocks: 32768, 98304, 163840, 229376, 294912
390
Verteilte Datenhaltung
Writing inode tables: done Creating journal (8192 blocks): done Writing superblocks and filesystem accounting information: done This filesystem will be automatically checked every 21 mounts or 180 days, whichever comes first. Use tune2fs -c or -i to override.
Wenn Sie versuchen, diese Operation auf dem nicht aktiven Node, dem Secondary, auszuführen, erhalten Sie eine Fehlermeldung: # sudo mkfs.ext3 /dev/drbd0 mke2fs 1.40.8 (13-Mar-2008) mkfs.ext3: Wrong medium type while trying to determine filesystem si ze
Das ist korrekt, denn nur der Primary darf schreibend auf die gespiegelte Partition zugreifen. Mit drbdadm können Sie den Status des DRBD-RAIDs abfragen. Auf dem Primary ist die Ausgabe des Status wie folgt: # drbdadm state data Primary/Secondary
Auf dem Secondary ist die Reihenfolge umgekehrt: # drbdadm state data Secondary/Primary
Der Parameter data ist der Name der abzufragenden DRBD-Ressource, der in der Datei /etc/drbd.conf im entsprechenden Ressource-Abschnitt konfiguriert ist. Nach dem Einrichten der Partition und des Dateisystems können Sie das DRBDBlockdevice in ein beliebiges Verzeichnis mounten: # sudo mount /dev/drbd0 /data # ls -la /data/ total 28 drwxr-xr-x+ 3 root root 4096 2008-09-25 22:22 . drwxr-xr-x+ 23 root root 4096 2008-09-25 22:27 .. drwx------+ 2 root root 16384 2008-09-25 22:22 lost+found
Um zu kontrollieren, ob die Synchronisation funktioniert, legen Sie eine Datei in diesem Verzeichnis an: # touch /data/foo # ls -la /data/ total 32 drwxr-xr-x+ 3 root root
Um zwischen Primary und Secondary zu wechseln, verwenden Sie das Programm drbdadm. Im ersten Schritt machen Sie den Primary zum Secondary (gegebenenfalls müssen Sie vorher noch das DRBD-Blockdevice unmounten). # sudo drbdadm secondary data
Im Syslog quittiert DRBD diesen Befehl mit der entsprechenden Ausgabe: drbd0: role( Primary -> Secondary )
Den Secondary machen Sie auf die gleiche Weise zum Primary: # drbdadm primary data
Auch hier zeigt der Syslog die Veränderung an und auch, dass der eigentliche Primary vorher seine Rolle getauscht hat: drbd0: peer( Primary -> Secondary ) drbd0: role( Secondary -> Primary )
Auf dem ehemaligen Secondary können Sie nun das DRBD-Blockdevice mounten: # sudo mount /dev/drbd0 /data
Der Inhalt ist derselbe wie auf dem ehemaligen Primary: # ls -la /data/ total 32 drwxr-xr-x+ 3 root drwxr-xr-x+ 23 root -rw-r--r--+ 1 root drwx------+ 2 root
root 4096 root 4096 root 0 root 16384
2008-09-25 2008-09-24 2008-09-25 2008-09-25
22:27 23:33 22:27 22:22
. .. foo lost+found
Verwaltung von Ressourcen Genau wie bei Heartbeat gilt auch bei DRBD die eiserne Regel, dass vom Programm verwaltete Ressourcen nicht zusätzlich auch noch manuell oder automatisiert gestartet werden dürfen. Die von DRBD zu verwendende Partition darf daher unter keinen Umständen über die Datei /etc/fstab dem System zugänglich gemacht oder über sonstige Mechanismen beschrieben werden. Die Arbeit mit der Partition obliegt einzig und allein DRBD, alles andere führt geradewegs in unüberschaubare Probleme mit inkonsistenten oder zerstörten Daten!
392
Verteilte Datenhaltung
6.3.4
Integration mit Heartbeat
Dass DRBD funktioniert, hat das vorstehende Beispiel während der Einrichtung gezeigt. Es hat allerdings auch veranschaulicht, dass das Wechseln von Primary und Secondary keine Aufgabe ist, die sich im Notfall manuell durchführen lässt. Da auf einem 2-Node-Verbund, in dem man mit DRBD Daten spiegeln möchte, aber ohnehin in der Regel ein Heartbeat-Cluster läuft, ist die Integration von DRBD in diesen Cluster ein naheliegender Gedanke. Glücklicherweise so naheliegend, dass die Programmierer von DRBD auch auf diesen Gedanken gekommen sind, so dass die Integration in der Praxis keine ausgeprägten Hürden aufstellt. Im Zusammenhang mit DRBD kommt Heartbeat im traditionellen Modus, also nicht dem CRM von Heartbeat2, eine zusätzliche Bedeutung zu, denn ein DRBDVerbund unterstützt nur maximal zwei Nodes, so dass auch ein Cluster mit mehr als zwei Nodes nicht sinnvoll wäre. Voraussetzung für die Integration von DRBD in Heartbeat sind zwei Nodes mit je einer funktionierenden Heartbeat- und einer DRBD-Installation. Alles, was Sie dann noch anpassen müssen, ist die Datei /etc/ha.d/haresources auf beiden Cluster-Nodes. Die in Abschnitt 6.2.2 verwendete Beispielkonfiguration von Heartbeat erweitert sich – auf beiden Nodes – wie folgt: hardy 192.168.0.25 dev/drbd0::/data::ext3
apache2
drbddisk::data
Filesystem::/
Die ersten drei Spalten bleiben unverändert: Master-Node, virtuelle IP-Adresse und zu startender Init-Dienst. In der vierten Spalte legen Sie über den Eintrag drbddisk::data fest, dass Heartbeat auch DRBD verwalten soll, und zwar mit der DRBD-Ressource data. Die vierte Spalte legt noch das zu verwendende DRBDBlockdevice, das Zielverzeichnis, in das Heartbeat das Blockdevice mounten soll, und das Dateisystem des Blockdevices fest. Nach einem Neustart von Heartbeat auf beiden Nodes ist auf dem jeweils aktiven Node das DRBD-Blockdevice im Verzeichnis /data gemounted: # df -h Filesystem /dev/sda2 varrun varlock udev devshm /dev/drbd0
Änderungen auf dem DRBD-Blockdevice sind nach dem Schwenk des Clusters ohne Verzögerungen auf dem neuen Master-Node sichtbar, wie die nachfolgen-
393
6.3
6
Hochverfügbarkeit
den Listings zeigen. Der Host hardy ist zunächst Master-Node und hat das DRBDBlockdevice unter /data gemounted. Nach dem Schwenk ist hardy2 Master, und die auf hardy erstellte Datei /data/foobar ist auch auf hardy2 verfügbar. [23:26:56] --- kr@hardy:/ # touch /data/foobar [23:27:13] --- kr@hardy:/ # ls -la /data/ total 36 drwxr-xr-x+ 3 root root 4096 2008-09-25 drwxr-xr-x+ 23 root root 4096 2008-09-25 -rw-r--r--+ 1 root root 0 2008-09-25 -rw-r--r--+ 1 root root 0 2008-09-25 drwx------+ 2 root root 16384 2008-09-25 [23:27:17] --- kr@hardy:/ # sudo /etc/init.d/heartbeat stop [...] [23:26:22] --- kr@hardy2:~ # ls -la /data/ total 36 drwxr-xr-x+ 3 root root 4096 2008-09-25 drwxr-xr-x+ 23 root root 4096 2008-09-24 -rw-r--r--+ 1 root root 0 2008-09-25 -rw-r--r--+ 1 root root 0 2008-09-25 drwx------+ 2 root root 16384 2008-09-25
23:27 23:25 22:27 23:27 22:22
. .. foo foobar lost+found
23:27 23:33 22:27 23:27 22:22
. .. foo foobar lost+found
Datensicherheit mit DRBD Die Datensicherheit innerhalb eines DRBD-Verbundes entspricht der Datensicherheit eines RAID-1-Systems. Das bedeutet, dass DRBD kein Ersatz für eine Datensicherung ist und der Ausfall eines DRBD-Nodes unmittelbares Eingreifen erfordert, um Datenverluste zu vermeiden. Sobald ein Node ausfällt, gibt es keine Datenspiegelung mehr, und der verbleibende Node stellt damit einen Single-Point-of-Failure da. Alle Änderungen, die der Primary auf das gespiegelte DRBD-Blockdevice schreibt, sind unmittelbar auch auf dem Datenspeicher der Secondary vorhanden. Daher ist eine Datensicherung, zusätzlich zur DRBD-Spiegelung, unerlässlich, um logische Fehler in der Datenhaltung, z. B. durch Anwender- oder Softwarefehler, rückgängig machen zu können. Betrachten Sie einen DRBD-Verbund immer als eine logische Festplatte – mit allen Vor- und Nachteilen.
394
»Ihre Doppel-Null-Nummer bedeutet: Sie dürfen notfalls einen Gegner erschießen – nicht er Sie!« M.
7
Serverwartung
Einen Server im Internet zu betreiben ist ein ständiges Katz-und-Maus-Spiel mit den Angreifern. Ob Skript-Kiddie, gewiefter Hacker oder Ganove mit kommerziellen Absichten – es gibt genügend Personen, die es auf Ihren Server abgesehen haben könnten, weswegen die Installation und Konfiguration eines Systems nur die halbe Miete ist. Die ständige Wartung, um Sicherheitslücken zu schließen und/oder zu vermeiden, ist der Rest der Miete. Nun ist das Installieren und Einrichten eines Servers für einen Administrator eine spannende und abwechslungsreiche Angelegenheit. Anders sieht es mit dem Betrieb aus, und hier spreche ich auch aus eigener Erfahrung. Die Betreuung eines Systems ist mit viel Routinearbeit verbunden und wird schnell langweilig. Neue Features auszuprobieren weckt den Spieltrieb, nach Updates zu schauen und diese über den Paketmanager einzuspielen eher nicht. Dabei ist genau diese Arbeit für die Sicherheit eines Systems unerlässlich und muss gewissenhaft, regelmäßig und in Notfällen auch umgehend stattfinden. Notfälle können z. B. das Bekanntwerden von 0-Day-Exploits sein. Darunter versteht man Sicherheitslücken, die zum Zeitpunkt ihres Bekanntwerdens bereits von Angreifern ausgenutzt werden oder für die es bereits fertige Angriffstools gibt, bevor ein Patch zur Verfügung steht. Normalerweise reagieren die verschiedenen Distributionsanbieter sehr schnell auf bekanntgewordene Sicherheitslücken. Ubuntu ist in diesem Bereich vorbildlich, bei Gentoo sieht die Situation allerdings nicht immer rosig aus, da kann es unter Umständen notwendig sein, eine installierte Software selbständig zu patchen, d. h. den Quelltext zu ändern und die Software anschließend neu zu kompilieren. Dieser Weg ist nur für Administratoren mit Programmierkenntnissen und viel Zeit gangbar, für den professionellen Einsatz ist so ein Vorgehen allerdings vollkommen ungeeignet.
395
7
Serverwartung
7.1
Tools
Wartung und Pflege eines einzelnen Systems lassen sich über die herkömmliche Methode mit den entsprechenden Kommandozeilen-Tools (apt-get und emerge) problemlos erledigen. Schwieriger wird es, sobald Sie mehrere Systeme warten müssen, denn dann stoßen die Kommandozeilen-Tools schnell an ihre Grenzen, und der Bedarf für eine zentrale Lösung wächst. Für Gentoo ist keine Lösung bekannt, mit der sich die Wartung zentralisieren und vereinfachen lässt. Canonical, der Hersteller der Ubuntu-Distribution, bietet hingegen ein kommerzielles Programm zur Administration von Ubuntu-Systemen an. Dieses Programm – Landscape – ist aufgrund seines Preises für die Administration eines einzelnen Systems möglicherweise etwas zu viel des Guten, wenn Sie allerdings mehr als ein Ubuntu-System administrieren, werden Sie den Komfort einer solchen Administrationslösung schnell zu schätzen lernen. Abgesehen von einer zentralisierten Lösung für die komfortable Verwaltung mehrerer Systeme ist es auch für einen Administrator nur eines einzigen Systems sehr hilfreich, wenn er proaktiv vom System darüber unterrichtet wird, dass Updates vorliegen. Sowohl Ubuntu als auch Gentoo verfügen über einen Paketmanager, mit dem sich der Stand des Systems mit den jeweiligen Update-Servern vergleichen lässt. Die entsprechenden Tools der Paketmanager lassen sich leicht in zentrale Überwachungen wie z. B. Nagios einbauen, so dass die Einrichtung eines eigenen Systems zur Benachrichtigung über das Vorliegen neuer Updates entfällt.
7.2
Patchmanagement
Software ist fehleranfällig, und mit der Komplexität einer Software wächst die Wahrscheinlichkeit von Fehlern in dieser Software. Sicherheitslücken sind ebenfalls Fehler, und zwar solche, die ein Angreifer ausnutzen kann, um die Software oder ein System zu kompromittieren oder deren Betrieb zu stören. Der LinuxKernel mit seinen knapp 6 Millionen Zeilen Sourcecode ist ein gutes Beispiel für die Komplexität aktueller Softwareprojekte. Bedenkt man dabei, dass der Kernel zwar der wichtigste, prozentual gesehen aber nur ein kleiner Teil eines Linux-Systems ist, lässt sich ungefähr abschätzen, wie komplex eine komplette Linux-Distribution ist. Bekanntgewordene Sicherheitslücken werden in der Regel über entsprechende Updates der betroffenen Software behoben. Auf einem durchschnittlichen LinuxSystem können sich mitunter Tausende von Softwarepaketen befinden, so dass ein Administrator gar nicht alle Pakete kennen und händisch pflegen kann. Ihn
396
Patchmanagement
dabei zu unterstützen ist die Aufgabe des Paketmanagers einer Distribution. Alle über den Paketmanager eingespielten Pakete sind diesem bekannt und können durch die Update-Funktionalität automatisch mit Updates versorgt werden. Unter Ubuntu steht mit apt-get und unter Gentoo mit emerge ein leistungsfähiges Tool für das praktische Patchmanagement zur Verfügung. Patchmanagement-Qualität der Distributionen 2006 hat die Website SearchSecurity.com eine Untersuchung über die Geschwindigkeit durchgeführt, mit der verschiedene Distributoren nach dem Bekanntwerden von Sicherheitslücken Updates bereitstellen. Am besten hat Ubuntu abgeschnitten mit einer Bewertung von 76 Punkten. Gentoo lag mit 39 Punkten schon relativ weit hinten, SuSE Linux Enterprise mit 32 Punkten noch dahinter. Interessant ist die Erwähnung von SuSE Linux Enterprise, weil diese Distribution kostenpflichtig ist. Das schlechte Abschneiden von Gentoo spricht nicht für die Distribution.
7.2.1
Patchmanagement mit Ubuntu
Im bisherigen Verlauf des Buches haben Sie bereits häufiger die Bekanntschaft mit apt-get gemacht, dem Benutzer-Interface zum Paketmanager APT von Ubuntu. Dieser ist auch für das Prüfen auf neue Updates und das anschließende Installieren derselben zuständig. Um zu prüfen, ob neue Updates vorliegen, vergleicht APT die Liste der installierten Pakete mit der Liste der Pakete auf den Installationsservern und prüft anhand der Versionsnummern, ob neue Pakete zu installieren sind. Der Update-Vorgang besteht aus zwei Durchläufen. Im ersten Schritt wird die aktuelle Liste der Paketversionen von den Installationsservern geholt und mit der lokalen Liste verglichen. Ergeben sich Änderungen, besteht der zweite Schritt darin, die geänderten Pakete von den jeweiligen Servern herunterzuladen und zu installieren. Beim manuellen Aufruf von apt-get können Sie die aktuelle Liste der Pakete über den Schalter update von den Installationsservern laden: # sudo apt-get update OK http://security.ubuntu.com hardy-security Release.gpg Ign http://security.ubuntu.com hardy-security/main Translation-de OK http://de.archive.ubuntu.com hardy Release.gpg OK http://de.archive.ubuntu.com hardy/main Translation-de [...] OK http://de.archive.ubuntu.com hardy-updates/main Packages OK http://de.archive.ubuntu.com hardy-updates/universe Packages OK http://de.archive.ubuntu.com hardy-updates/universe Sources Paketlisten werden gelesen... Fertig
397
7.2
7
Serverwartung
apt-get lädt von jeder in der Datei /etc/apt/sources.list aktivierten Installations-
quelle die aktuelle Paketliste herunter und speichert sie im Verzeichnis /var/lib/ apt/lists. In den Listen sind die für den Paketmanager notwendigen Meta-Angaben der auf dem jeweiligen Server erhältlichen Programmpakete gespeichert. Als Beispiel finden Sie nachfolgend die Beschreibung des Paketes ruby1.8: Package: ruby1.8 Binary: ruby1.8, libruby1.8, libruby1.8-dbg, ruby1.8-dev, libdbmruby1.8, libgdbm-ruby1.8, libreadline-ruby1.8, libtcltkruby1.8, libopenssl-ruby1.8, ruby1.8-examples, ruby1.8elisp, ri1.8, rdoc1.8, irb1.8 Version: 1.8.6.111-2ubuntu1.1 Priority: optional Section: interpreters Maintainer: Ubuntu Core developers Original-Maintainer: akira yamada Build-Depends: autoconf, autotoolsdev, binutils (>= 2.14.90.0.7), bison, cdbs, debhelper (>= 5), dpatc h, gcc-4.1 (>= 4.1.1-11) [m68k], libgdbm-dev, libncurses5-dev, libreadline5-dev, libssl-dev (>= 0.9.6b), m4, patch, tcl8.4-dev, tk8.4-dev, zlib1g-dev Architecture: any Standards-Version: 3.7.2 Format: 1.0 Directory: pool/main/r/ruby1.8 Files: 9d4620930aca9a2769eed7dac86decd8 1163 ruby1.8_1.8.6.111-2ubuntu1.1.dsc c36e011733a3a3be6f43ba27b7cd7485 4547579 ruby1.8_1.8.6.111.orig.tar.gz 0400122ad61b29499aa6ca210ed39002 46797 ruby1.8_1.8.6.111-2ubuntu1.1.diff.gz Uploaders: Fumitoshi UKAI , Daigo Moriwaki
Neben den Angaben zu Abhängigkeiten und der MD5-Hash-Werte der Programmpakete ist die Version der Paketes vermerkt: Version: 1.8.6.111-2ubuntu1.1
Die Version des bereits installierten Ruby-Paketes lässt sich mit dpkg herausfinden:
Die installierte Version weicht nicht von der Version auf dem Installationsserver ab; es ist kein Update notwendig. Welche Pakete ein Update benötigen, sehen Sie, wenn Sie den Update-Vorgang mit apt-get upgrade anstoßen: # sudo apt-get upgrade Paketlisten werden gelesen... Fertig Abhängigkeitsbaum wird aufgebaut Reading state information... Fertig Die folgenden Pakete sind zurückgehalten worden: bind9-host dnsutils libbind9-30 libisccfg30 linux-imageserver linux-server openssh-client openssh-server ssl-cert Die folgenden Pakete werden aktualisiert: firefox firefox-3.0 firefox-3.0-gnome-support firefox-gnomesupport gdb libc6 libc6-dev libc6-i686 libc6-xen python-gtkhtml2 xulrunner-1.9 xulrunner-1.9-gnome-support 12 aktualisiert, 0 neu installiert, 0 zu entfernen und 9 nicht aktua lisiert. Es müssen 22,0MB Archive geholt werden. After this operation, 41,0kB of additional disk space will be used. Möchten Sie fortfahren [J/n]? apt-get zeigt die Liste der Pakete an, die aktualisiert werden, und wartet auf eine Bestätigung, um mit dem Herunterladen und der Installation zu beginnen. Wichtig bei der vorstehenden Ausgabe von apt-get ist die folgende Zeile: Die folgenden Pakete sind zurückgehalten worden:
Damit zeigt apt-get an, dass für die als zurückgehalten markierten Pakete zwar Updates vorliegen, es diese Updates aber nicht automatisch einspielen wird, auch nicht nach der manuellen Bestätigung durch den Administrator. Überprüfen kön-
399
7.2
7
Serverwartung
nen Sie dies durch einen erneuten Aufruf von apt-get upgrade im Anschluss an den bereits durchgeführten Update-Vorgang: # apt-get upgrade Paketlisten werden gelesen... Fertig Abhängigkeitsbaum wird aufgebaut Reading state information... Fertig Die folgenden Pakete sind zurückgehalten worden: bind9-host dnsutils libbind9-30 libisccfg30 linux-image-server linux-server openssh-client openssh-server ssl-cert 0 aktualisiert, 0 neu installiert, 0 zu entfernen und 9 nicht aktualisiert.
Die betreffenden Pakete sind noch immer im Status »zurückgehalten« und wurden nicht aktualisiert. Das liegt in der Regel an Abhängigkeiten, die sich durch das Installieren dieser Pakete ändern würden. Die vorstehende Liste umfasst u. a. einen neuen Kernel, was bei Programmen wie z. B. VMware, die speziell angepasste Kernel-Module für den jeweils aktiven Kernel benötigen, zu einem Problem führt. Eine kommentarlose Installation der zurückgehaltenen Pakete über den normalen Update-Mechanismus könnte daher unbemerkt Probleme bereiten, weswegen diese Pakete über einen eigenen Befehl installiert werden: # sudo apt-get dist-upgrade Paketlisten werden gelesen... Fertig Abhängigkeitsbaum wird aufgebaut Reading state information... Fertig Berechne Upgrade...Fertig Die folgenden NEUEN Pakete werden installiert: libdns35 linux-image-2.6.24-19-server linux-ubuntu-modules-2.6.2419-server openssh-blacklist openssl-blacklist Die folgenden Pakete werden aktualisiert: bind9-host dnsutils libbind9-30 libisccfg30 linux-imageserver linux-server openssh-client openssh-server ssl-cert 9 aktualisiert, 5 neu installiert, 0 zu entfernen und 0 nicht aktual isiert. Es müssen 33,3MB Archive geholt werden. After this operation, 95,8MB of additional disk space will be used. Möchten Sie fortfahren [J/n]?
Auch hier ist eine manuelle Bestätigung notwendig, damit apt-get mit der Arbeit startet. Die Liste der zu installierenden Programme enthält in dem vorstehenden Beispiel auch den OpenSSH-Server, den OpenSSH-Client und SSL-Zert. Diese Pa-
400
Patchmanagement
kete werden im vorliegenden Fall nur über dist-upgrade eingespielt, da mit den neuen Versionen ein schwerer Bug behoben wird, der möglicherweise die Erstellung neuer SSH-Keys für das System oder lokale Benutzer nach sich zieht (Abbildung 7.1 und Abbildung 7.2).
Abbildung 7.1
Abfrage von apt-get dist-upgrade
Da dies naheliegenderweise ein schwerer Eingriff ist, der nur gut geplant durch den Administrator durchgeführt werden darf, ist dieses Beispiel ausgezeichnet geeignet, um den Sinn der zurückgehaltenen Pakete zu erläutern.
Abbildung 7.2
Information beim Update-Vorgang
»Der« Debian-Bug Am 13.05.2008 wurde vom Debian-Team eine Sicherheitsankündigung zum OpenSSLPaket herausgegeben: http://www.debian.org/security/2008/dsa-1571
401
7.2
7
Serverwartung
Sicherheitsankündigungen, auch für sicherheitsrelevante Pakete, sind keine Seltenheit, und so haben viele Benutzer die außergewöhnliche Brisanz dieser Ankündigung erst im Nachhinein verstanden. Die Ankündigung besagte, dass am 17.09.2006 eine Änderung am OpenSSL-Paket in den offiziellen Debian-Zweig aufgenommen wurde, die zur Folge hatte, dass über SSL generierte Zufallsoperationen nur noch eine maximale Entropie von 32.768 aufwiesen. Der Grund dafür war eine Änderung im Sourcecode, den ein Entwickler vorgenommen hatte, weil ihn Compiler-Warnungen beim Übersetzen gestört hatten. Als Folge davon sind alle zwischen dem 17.09.2006 und dem 13.08.2008 unter Debian – und damit auch unter Ubuntu – erstellten SSH- und SSL-Schlüssel in hohem Maße durch Brute-Force-Angriffe gefährdet, da ein Angreifer lediglich 32,768 verschiedene Schlüssel zu testen braucht. Eine Zusammenfassung der Problematik samt passender Tools zum Prüfen der eigenen Schlüssel bietet H. D. Moore auf der Website seines Metasploit-Projektes: http://www.metasploit.com/users/hdm/tools/debian-openssl/
Dieser Vorfall zeigt sehr deutlich die Gefahren einer nicht geregelten Software-Entwicklung im Sinne eines Secure Software Development Lifecycle (SSDL). Darüber hinaus räumt dieser Vorfall auch mit dem Argument auf, Open-Source-Software sei per se sicher, da die Software ja einer ständigen Kontrolle durch viele Augen unterliege. Dass eine so eklatante Sicherheitslücke in einem so zentralen und sicherheitskritischen Paket über einen so langen Zeitraum unentdeckt geblieben ist, sollte jeden Befürworter von Open Source zumindest nachdenklich stimmen. In diesem Zusammenhang ist auch noch eine Aussage des Bundesamtes für Sicherheit in der Informationstechnik (BSI) interessant: »Für den Fall, dass Schwachstellen neu entdeckt werden, die einen DoS-Angriff ermöglichen oder erleichtern, ist es wichtig, dass diese schnell behoben werden können. Meist werden derartige Schwachstellen in Open-Source-Software wesentlich schneller behoben als in Produkten, deren Quellcode nicht veröffentlicht ist. Häufig können die Veränderungen im Quellcode sogar selbst durchgeführt werden. Daher sollten OpenSource-Produkte bei ähnlicher Leistungsfähigkeit bevorzugt werden.« http://www.bsi.de/fachthem/sinet/gefahr/ddos.htm
Nun denn …
Nach dem erfolgreichen Durchlauf von apt-get dist-upgrade führt ein erneuter Aufruf von apt-get upgrade zu dem folgenden Ergebnis: # sudo apt-get upgrade Paketlisten werden gelesen... Fertig Abhängigkeitsbaum wird aufgebaut Reading state information... Fertig 0 aktualisiert, 0 neu installiert, 0 zu entfernen und 0 nicht aktualisiert.
Damit haben Sie eine perfekte Grundlage, um das Patchmanagement so weit zu automatisieren, dass Sie mit Nagios das Vorliegen neuer Patches überprüfen können. Rufen Sie über ein Nagios-Plugin zunächst apt-get update auf und anschlie-
402
Patchmanagement
ßend apt-get upgrade. Wenn apt-get upgrade die vorstehende Ausgabe erzeugt, liegen keine Updates vor, und das Plugin gibt als Rückgabewert OK zurück – in Nagios ist alles im grünen Bereich. Die Ausgabe von apt-get upgrade können Sie durch den geschickten Einsatz von grep und awk so anpassen, dass sie in ein Nagios-Plugin passt (nur eine Zeile ist erlaubt): # apt-get upgrade|grep aktualisiert | awk ' { printf("%s %s %s %s ", $1,$3,$6,$10)}'
Über den Aufruf von grep schneiden Sie die Zeile aus, in der die Anzahl der zu aktualisierenden Pakete steht. Mit awk können Sie aus dieser Zeile die vier Ziffern extrahieren, so dass im Normalzustand – keine Updates vorhanden – die Ausgabe aus vier Nullen besteht: 0 0 0 0 Sobald ein Update vorliegt, besteht die Ausgabe nicht mehr aus vier Nullen, das Nagios-Plugin liefert einen anderen Rückgabewert, und der Administrator weiß, dass er eingreifen muss. apt-get update und apt-get upgrade laufen ausgesprochen schnell – nur wenige Sekunden reichen, um den aktuellen Status des Systems zu ermitteln. Daher können beide Aufrufe problemlos in einem Skript verwendet werden, dass z. B. über ein Nagios-Plugin aufgerufen wird. Vorsicht mit automatischem Patchmanagement apt-get bietet die Möglichkeit, über den Schalter -y die Abfrage einer manuellen Re-
aktion zu unterdrücken, um so automatisiert ohne Dialog mit dem Benutzer Updates einspielen zu können. Dieses auf den ersten Blick verlockend einfache Vorgehen ist in der Praxis gefährlich und nicht empfehlenswert. Updates können Nebenwirkungen haben, so dass in jedem Fall der Administrator einen letzten Blick auf die zu erwartenden Änderungen werfen sollte. Fehlgeschlagene Kernel-Updates können zu unbenutzbaren Systemen führen, und wenn so etwas inklusive Reboot automatisiert am Freitag Abend geschieht und der Administrator erst am Montag wieder nach dem Server schaut, ist das für Betreiber und Kunden kein wünschenswerter Zustand.
Für die Arbeit mit bereits installierten Paketen ist das Tool dpkg zuständig. Mitunter kann es vorkommen, dass eine Liste der installierten Pakete erzeugt werden muss, dann hilft dpkg über den Schalter –l: # dpkg -l|more Desired=Unknown/Install/Remove/Purge/Hold | Status=Not/Installed/Config-f/Unpacked/Failed-cfg/Half-inst/taWait/T-pend |/ Err?=(none)/Hold/Reinst-required/X=both-problems (Status,Err: uppercase=bad) ||/ Name Version Beschreibung ii acl 2.2.45-1 Access control list utilities ii acpi 0.09-3ubuntu1 displays information on ACPI devices
403
7.2
7
Serverwartung
ii acpi-support for acpi [...]
0.109
a collection of useful events
Die zu einem Paket gehörenden Dateien gibt dpkg über den Schalter –L aus: # dpkg -L apache2.2-common|more /. /etc /etc/apache2 /etc/apache2/mods-enabled /etc/apache2/sites-enabled /etc/apache2/conf.d /etc/apache2/conf.d/charset /etc/apache2/apache2.conf /etc/apache2/envvars /etc/apache2/mods-available /etc/apache2/mods-available/actions.conf /etc/apache2/mods-available/info.load /etc/apache2/mods-available/mem_cache.load /etc/apache2/mods-available/speling.load /etc/apache2/mods-available/dav_fs.load [...]
Und wenn Sie wissen möchten, zu welchem Paket eine Datei gehört, rufen Sie dpkg mit –S und dem Dateinamen samt Pfad auf: # dpkg -S /etc/ha.d/harc heartbeat: /etc/ha.d/harc
Ohne Kommentar »Es sollte nicht von Paketbetreuern verwendet werden, die verstehen wollen, wie dpkg ihr Paket installieren wird. Die Beschreibung von den Tätigkeiten von dpkg beim Installieren und Entfernen von Paketen ist besonders unzulänglich.« (Manpage von dpkg)
7.2.2
Patchmanagement mit Gentoo
Unter Gentoo ist emerge die Schnittstelle zum Paketmanager und somit auch für das Pflegen des Systems zuständig. Genau wie bei Ubuntu muss auch unter Gentoo vor dem Update eine aktuelle Liste der auf den Installationsservern verfügbaren Pakete erstellt und mit der Liste der lokal installierten Pakete verglichen werden. Das Erstellen der Liste von den Installationsservern erfolgt über das Synchronisieren des Portage-Baums: # sudo emerge --sync
404
Patchmanagement
In der Ausführung dieses Befehls liegt schon das erste Problem des Patchmanagements unter Gentoo. Das Synchronisieren kann in Abhängigkeit von der Qualität der Netzwerkverbindung mitunter 10–20 Minuten in Anspruch nehmen. Während des Synchronisierungsvorgangs erzeugt emerge eine recht hohe Last auf dem System. Eine Verwendung in einem Skript – analog zu apt-get update – scheidet damit aus. Sie sollten den Vorgang daher per Cron-Job gesteuert regelmäßig zu einer ruhigen Zeit ausführen, z. B. einmal pro Nacht. Nach der Synchronisierung des Portage-Baums stoßen Sie das Update über den folgenden Befehl an: # sudo emerge –auD world
Beziehungsweise in ausführlicher Notation: # sudo emerge --ask --update --deep world
Je nach Zeitraum kann die Liste der zu aktualisierenden Pakete sehr umfangreich sein. Bedenken Sie dabei, dass jedes Paket aus dem Quelltext übersetzt werden muss. Der Update-Vorgang kann daher in Abhängigkeit von den zu übersetzenden Paketen einige Stunden in Anspruch nehmen. Für die Arbeit mit lokalen Paketen ist emerge nicht geeignet, dafür steht aber das Programm equery zur Verfügung und bietet umfangreiche Möglichkeiten. Falls nicht bereits installiert, können Sie equery über das Paket gentoolkit installieren: # sudo emerge gentoolkit
Eine Liste der installierten Pakete erhalten Sie über den Parameter list: # equery list * installed packages app-accessibility/brltty-3.9 app-admin/eselect-1.0.10 app-admin/eselect-ctags-1.3 app-admin/eselect-esd-20060719 app-admin/eselect-fontconfig-1.0 app-admin/eselect-opengl-1.0.5 app-admin/eselect-vi-1.1.5 app-admin/eselect-wxwidgets-0.7-r1 app-admin/gamin-0.1.9 [...]
Möchten Sie wissen, zu welchem Paket eine Datei gehört, verwenden Sie den Parameter belongs, gefolgt von Pfad und Namen der Datei:
405
7.2
7
Serverwartung
# equery belongs /etc/screenrc [ Searching for file(s) /etc/screenrc in *... ] app-misc/screen-4.0.3 (/etc/screenrc)
Eine Liste aller Dateien eines Paketes gibt der Parameter files gefolgt vom Paketnamen aus: # equery files gentoolkit|more /etc /etc/eclean /etc/eclean/distfiles.exclude /etc/eclean/packages.exclude /etc/env.d /etc/env.d/99gentoolkit-env /etc/revdep-rebuild /etc/revdep-rebuild/99revdep-rebuild /usr /usr/bin /usr/bin/eclean /usr/bin/eclean-dist /usr/bin/eclean-pkg /usr/bin/equery /usr/bin/eread /usr/bin/euse /usr/bin/glsa-check [...]
Sehr interessant ist auch die Möglichkeit, die Abhängigkeiten eines Paketes zu visualisieren: # equery depgraph gentoolkit [ Searching for packages matching gentoolkit... ] * dependency graph for app-portage/gentoolkit-0.2.3-r1 `-- app-portage/gentoolkit-0.2.3-r1 `-- sys-apps/portage-2.1.4.4 `-- dev-lang/python-2.4.4-r13 `-- sys-libs/zlib-1.2.3-r1 `-- dev-lang/tk-8.4.15-r1 [ !build tk ] `-- x11-libs/libX11-1.1.4 `-- x11-libs/xtrans-1.0.3 `-- sys-devel/automake-1.10.1 [...]
Gentoo-spezifisch ist die Suche nach bestimmten USE-Flags in der Liste der installierten Pakete: # equery hasuse ssl [ Searching for USE flag ssl in all categories among: ]
Umgekehrt können Sie mit equery auch die USE-Flags eines bestimmten Paketes anzeigen lassen: # equery uses nmap [ Searching for packages matching nmap... ] [ Colour Code : set unset ] [Legend: Left column (U) - USE flags from make.conf] [ : Right column (I) - USE flags packages was installed with ] [ Found these USE variables for net-analyzer/nmap-4.50 ] U I + + gtk : Adds support for x11-libs/gtk+ (The GIMP Toolkit) + + ssl : Adds support for Secure Socket Layer connections
Leidvolles Patchmanagement mit Gentoo Patchmanagement ist unter Gentoo das, was Amerikaner als »pain in the a...« bezeichnen. Selten läuft ein emerge world ohne Probleme durch. Das geringste Übel sind dabei sich gegenseitig blockierende Pakete, was auch im Nachhinein immer wieder durch andere Flags entstehen kann. Das größere Problem sind Konfigurationsdateien, deren Format oder Syntax sich verändert hat, oder Fehler beim Übersetzen einzelner, mitunter wichtiger Pakete, was dazu führt, dass sich das gesamte System nicht mehr starten lässt. Wohl demjenigen, der dann mit einer Boot-CD bewaffnet in der Nähe seines Servers sitzt. Aus eigener Erfahrung im professionellen Einsatz von Gentoo würde ich die Quote der ohne Probleme geglückten Update-Durchläufe auf 1:10 setzen – von zehn Durchläufen funktioniert ein einziger ohne Probleme oder manuelle Nacharbeit.
407
7.2
7
Serverwartung
7.2.3
Schwierigkeiten beim Patchmanagement
Patchmanagement ist wichtig und für die kontinuierliche Sicherheit eines Systems unerlässlich. Allerdings gibt es immer wieder Stolpersteine zu beachten. Der größte Stolperstein beim Patchen von Ubuntu und Gentoo ist die fehlende Vorhersagbarkeit von Terminen für das Erscheinen von Updates. Die Firma Microsoft ist da schon weiter und bringt Updates jeden Monat am gleichen Tag heraus. Anfangs belächelt, ist dieses Vorgehen für Administratoren allerdings sehr angenehm, da es die Wartungsarbeiten planbar macht. Ubuntu und Gentoo veröffentlichen Updates unregelmäßig, was dazu führt, dass ein Administrator ständig das Vorhandensein neuer Updates prüfen muss. Dies lässt sich automatisieren (siehe Abschnitt 7.2.1), erlaubt aber keine sinnvolle Disposition von Arbeitszeit. Zwar veröffentlicht auch Microsoft außerhalb des Patchdays Updates für besonders sicherheitskritische Lücken, grundsätzlich bringt der Patchday aber eine wesentlich bessere Planbarkeit für den Administrator, insbesondere wenn viele Systeme zu warten sind. Besonderes Augenmerk sollten Sie auf Applikationen legen, die vom Patchmanagement der Distribution Ihrer Wahl nicht erfasst werden. Das ist bei einem Webserver mit an Sicherheit grenzender Wahrscheinlichkeit die Webapplikation. Davon abgesehen, dass niemand die Sicherheit dieser Applikation untersucht – es sei denn, dass Sie oder Ihr Programmierer das selbst machen –, ist diese Applikation obendrein auch noch vom Internet erreichbar und damit Einfallstor Nummer eins für Angreifer. Angriffe auf Netzwerkebene nehmen stetig ab, denn so gut wie jedes System oder Netzwerk ist heutzutage durch eine Firewall geschützt. Damit verlagern sich Angriffe immer mehr auf die Applikationsebene, also auf die Webapplikationen. Der 2008 Data Breach Investigations Report der Firma Verizon besagt, dass bereits 39 % aller Angriffe auf Applikationsebene stattfinden und nur noch 23 % auf Betriebssystem-Ebene. Darüber hinaus erforderten nach diesem Report 52 % aller erfolgreichen Angriffe nur ein niedriges Know-how des Angreifers. Achten Sie daher auf eine robuste Programmierung Ihrer Webapplikation. Wenn Sie ein Open-Source-Produkt wie z. B. Mambo oder phpBB verwenden, sollten Sie ständig die einschlägigen Sicherheitsmeldungen verfolgen und beim Bekanntwerden einer Sicherheitslücke die Software umgehend updaten. Gerade Sicherheitslücken in solch weitverbreiteten Applikationen sind wiederholt in der Vergangenheit nach Bekanntwerden automatisiert und in rasender Geschwindigkeit ausgenutzt worden. Daher der dringende Rat: Das Pflegen der Distributionspakete ist nur die halbe Miete. Denken Sie an Ihre eigenen und exponierten Applikationen, diese stellen den größten Angriffsvektor dar!
408
Den Überblick behalten
Was passiert im Urlaub? Guter Tipp: Behandeln Sie Ihren Server wie eine Pflanze. Das bedeutet nicht, dass Sie ihn mit einer Gießkanne gießen sollen, aber sorgen Sie für die Pflege des Systems, wenn Sie sich selbst länger nicht darum kümmern können, beispielsweise während Ihres Urlaubs. Sicherheitslücken tauchen nicht immer nur dann auf, wenn der Administrator verfügbar ist, sondern auch und nach Murphys Gesetz insbesondere dann, wenn der Zeitpunkt am ungünstigsten ist. Daher sollten Sie für diesen Fall vorsorgen und einen Vertreter damit betrauen, die Verfügbarkeit von Updates zu prüfen und diese gegebenenfalls zu installieren, während Sie sich faul in der Sonne räkeln.
7.3
Den Überblick behalten
Trotz automatisiertem Updateservice Ihrer Distribution ist es immer ratsam, ein Ohr am Puls der Zeit zu haben und die einschlägigen Quellen für sicherheitsrelevante Nachrichten regelmäßig zu konsultieren. Sicherheitslücken können bekannt werden, aber ein Distributor reagiert nicht innerhalb eines angemessenen Zeitraumes mit einem Update darauf. Handelt es sich um eine kritische Sicherheitslücke, sollten Sie eigene Gegenmaßnahmen durchführen, z. B. den betreffenden Dienst abschalten. Dies können Sie natürlich nur, wenn Sie überhaupt wissen, dass eine Sicherheitslücke vorliegt. Quellen für sicherheitsrelevante Meldungen gibt es viele. Jedes IT-Magazin, das etwas auf sich hält, hat eine eigene Rubrik für Sicherheitsmeldungen. Mailinglisten wie die berühmte Bugtraq1 oder Full-Disclosure2 dienen Sicherheitsexperten, Hackern und anderen Leuten im IT-Sicherheitsbusiness zum Erfahrungsaustausch und als Plattform für Sicherheitsankündigungen, so genannte Advisories. Behalten Sie diese Publikationen im Auge, um ungefähr zu wissen, welche Art von Bedrohung aktuell ist und welche Sicherheitslücken bestehen, aber möglicherweise auf Ihrem System noch nicht behoben sind. Darüber hinaus unterhalten Ubuntu und Gentoo eigene Informationsquellen für sicherheitsrelevante und distributionsbezogene Meldungen. Die aktuellen Meldungen von Ubuntu finden Sie unter http://www.ubuntu.com/usn oder als RSS-Feed unter http://www.ubuntu.com/taxonomy/term/2/0/feed. Gentoo betreibt unter der URL http://www.gentoo.org/security/en/index.xml eine Seite mit Sicherheitsinformationen rund um die Distribution und mit Links zu den aktuellen Gentoo Linux Security Announcements (GLSAs), auch als RSS-Feed: http://www.gentoo.org/rdf/en/ glsa-index.rdf
CERT – was ist das? 1984 veröffentlichte Fred Cohen seine Doktorarbeit über das Thema Computerviren und brachte das Thema damit in das Bewusstsein der Öffentlichkeit. Es sollten noch vier Jahre vergehen, bis Robert Morris den ersten Wurm der IT-Geschichte schrieb und auf das Internet losließ. Das als Morris-Wurm in die Geschichte eingegangene Programm infizierte innerhalb kurzer Zeit ca. 10 % aller Systeme im Internet. Als Reaktion auf diesen Schädling wurde das erste Computer Emergency Response Team (CERT) gegründet, damals an der bekannten Carnegie Mellon Universität3 in Pittsburgh. Seitdem hat sich der Begriff CERT eingebürgert und steht allgemein für eine Institution oder auch die Abteilung einer Firma, die Sicherheitsmeldungen analysiert und gegebenenfalls Warnungen und Gegenmaßnahmen für Sicherheitslücken veröffentlicht. Es gibt mittlerweile eine ganze Reihe deutschsprachiger CERTs, von denen die des deutschen Forschungsnetzes (http://www.cert.dfn.de/) und des Bundesamtes für Sicherheit in der Informationstechnik (http://www.bsi.de/certbund/) zu den bekanntesten zählen. Auf den Webseiten dieser (und anderer) CERTs erhalten Sie stets wichtige und interessante Informationen zu Sicherheitsvorfällen.
7.4
Rechtliches
Beim Betrieb eines eigenen Servers gibt es immer rechtliche Rahmenbedingungen zu beachten. Das fängt mit der Impressumspflicht für Webseiten an und hört damit auf, dass das Einsetzen eines Spam-Filters für E-Mail-Verkehr von Kunden nicht ohne deren ausdrücklichen Wunsch geschehen darf. Die juristischen Fußangeln sind vielfältig, und da es sich dabei nicht um Fragen der IT, sondern um juristische Fragestellungen handelt, sollten Sie im Zweifelsfall einen mit IT-Recht vertrauten Rechtsanwalt konsultieren. Dieser kann Ihnen nicht nur korrekte Angaben machen, sondern steht auch mit seiner Haftpflichtversicherung zur Verfügung, falls Sie durch eine Falschberatung Schaden erleiden und beispielweise zu Recht abgemahnt werden. Dieses Buch kann und darf eine juristische Beratung nicht ersetzen. Es kann aber Rahmenbedingungen erläutern, die im IT-Umfeld für die sichere Umsetzung von Informationssicherheit existieren. ISO 27001 Die ISO-Norm 27001 ist eine Unternorm der Normenreihe 27000. Ein Unternehmen, das die in der ISO 27001 definierten Anforderungen an den Betrieb eines ISMS erfüllt, kann sich von einer akkreditierten Institution diese Übereinstim3 http://www.cert.org/
410
Rechtliches
mung mit der Norm zertifizieren lassen. Als Richtlinie für die Zertifizierung dient dabei die ISO 27001. Damit ein Unternehmen die in dieser Norm geforderten Vorgaben erfüllen kann, kann es sich der Norm ISO 27002 bedienen (ehemals ISO 17799), die im Gegensatz zur ISO 27001 keine Prüfgrundlage ist, sondern Hilfe zur Implementierung bietet. Die Ziele eines ISMS sind das Gewährleisten von Integrität, Vertraulichkeit, Authentizität und Verfügbarkeit von Informationen. Dazu definiert die Norm verschiedene Richtlinien für den Betrieb eines ISMS. Diese Richtlinien sind nur für Firmen oder Institutionen interessant, die sich nach ISO 27001 zertifizieren lassen möchten. Interessant für Einzelpersonen und Betreiber von Servern ist hingegen der Anhang A der Norm, da dort in so genannten Control Clauses und Control Objectives konkrete Anforderungen an ein ISMS gestellt werden. Control Clauses sind Oberbegriffe, die Control Objectives enthalten. Nun werden Sie als Betreiber eines eigenen Servers nur wenige Berührungspunkte mit der ISO-Norm 27001 haben, nichtsdestotrotz sind einige der Control Objectives sehr hilfreich für den Betrieb eines sicheren Systems, denn sie können in der Diskussion mit Kunden oder Geschäftspartnern wie Providern ideal als Argumentationshilfe dienen. Auch kann es vorkommen, dass man auf seinem Server Dienste für einen Kunden betreibt, der sich nach ISO 27001 zertifizieren lassen möchte. Fällt der von Ihnen betriebene Server für den Kunden mit in den Rahmen der Zertifizierung, ist es sehr hilfreich, wenn sich Planung und Betrieb an den Vorgaben der ISO 27001 orientieren. Last, but not least sind die Anforderungen der Norm zwar recht generisch, bilden aber eine gute Basis für den sicheren Betrieb eines Systems. Insofern können sie mindestens als hilfreiche BestPractice-Anleitung dienen. Im Folgenden sind exemplarisch einige wichtige Control Objectives der ISO 27001 aufgeführt. Eine vollständige Übersicht enthält die Norm selbst, die Sie als urheberrechtlich geschütztes Werk kostenpflichtig bei der ISO beziehen können. Control Objective
Beschreibung
A.10.1.1 Stellen Sie sicher, dass Sie für eine ausreichende und gut verDokumentierte ständliche Dokumentation gesorgt haben. So können Sie die Verfahrensanweisungen Administration und Weiterentwicklung Ihres Servers auch einer anderen Person überlassen. A.10.1.2 Änderungsverwaltung
Tabelle 7.1
Protokollieren Sie alle Änderungen am System. Das können Änderungen an Konfigurationsdateien oder auch das Installieren oder Löschen von Paketen sein. Nur so können Sie sicherstellen, dass Sie im Fehlerfall auf einen alten Stand zurückwechseln können.
Exemplarische Anforderungen der ISO 27001
411
7.4
7
Serverwartung
Control Objective
Beschreibung
A.10.1.4 Trennen von Test- und Produktivsystemen
Trennen Sie Entwicklungs-, Test- und Produktivsysteme. Beim Betrieb eines einzelnen Servers ist Xen dabei das erste Mittel der Wahl. Damit können Sie einen dreistufigen Entwicklungsprozess realisieren, ohne dass Sie dazu drei Systeme benötigen.
A.10.5.1 Backup
Erstellen Sie regelmäßig Datensicherungen, und prüfen Sie regelmäßig das Funktionieren von Datensicherung und Restore.
A.10.7.4 Sicherheit von Systemdokumentation
Stellen Sie sicher, dass die Dokumentation zu Ihrem System, Ihrer Applikation o. Ä. sicher verwahrt und nicht für Unbefugte zugänglich ist.
Führen Sie Logfiles über alle wichtigen Benutzer- und Administratortätigkeiten am System, und schützen Sie die Logdateien gegen unbefugten Zugriff und vor nachträglicher Manipulation.
A.10.10.6 Zeitsynchronisation
Stellen Sie sicher, dass alle Rechner einer IT-Infrastruktur dieselbe synchronisierte Zeit haben.
A.12.2.1 Überprüfung von Eingabedaten
Alle Daten, die in eine Applikation eingegeben werden, müssen auf schädliche Zeichen oder Schadcode gefiltert werden. Dies ist bei Webapplikationen im Zusammenhang mit SQL-Injection und Cross Site Scripting von großer Bedeutung.
A.12.6.1 Kontrolle technischer Schwachstellen
Entspricht dem Abschnitt 7.3. Informieren Sie sich regelmäßig über Schwachstellen, und treffen Sie Maßnahmen, um Schwachstellen, die Ihr System betreffen, zu umgehen.
Tabelle 7.1
7.5
Exemplarische Anforderungen der ISO 27001 (Forts.)
Zusammenfassung
Im Verlaufe des Buches haben Sie verschiedene Vor- und Nachteile der beiden verwendeten Distributionen kennengelernt. Ubuntu ist zuverlässig, verfügt über ein exzellentes Patchmanagement und lässt in Bezug auf die Verfügbarkeit von Software keine Wünsche offen. Die verfügbaren Pakete sind durchweg in stabilen Versionen erhältlich. Ein Wermutstropfen ist die suboptimale Standardkonfiguration verschiedener Pakete, so z. B. die für den Produktivbetrieb viel zu geschwätzige Konfiguration des Apache-Webservers. Diese »Feinheiten« sollten im Rahmen eines Härtungskonzeptes beseitigt werden, dann steht mit Ubuntu ein solides und sicheres System für den eigenen Webserver zur Verfügung. Gentoo ist in vielen Dingen wesentlich anspruchsvoller als Ubuntu. Allein die Installation erfordert bereits sehr viel Detailwissen. Sobald es an ein Paket wie Xen geht, steht ein Benutzer ohne wirklich fundierte Kenntnisse über Linux im Regen.
412
Zusammenfassung
Hinzu kommen die Probleme beim Patchmanagement. Die Qualität desselben scheint eher mäßig zu sein, zumindest wenn man SearchSecurity.com glauben darf. Das eigentliche Problem taucht aber in der Praxis auf. Selten läuft ein Systemupdate ohne Probleme durch, das Aktualisieren vieler Pakete dauert durch die dafür notwendige Übersetzung aus dem Quelltext unverhältnismäßig lange, und im Anschluss daran sind häufig Detektiv- und Fleißarbeit angesagt, um das System in einen lauffähigen Zustand zu bringen. Wenn Sie sich davon aber nicht abschrecken lassen und sich genug Linux-Know-how zutrauen, um das Gentoo-Biest zu bändigen, haben Sie eine schlanke Distribution, die Sie perfekt an Ihre Bedürfnisse anpassen können.