139 74 12MB
German Pages 421 Year 2009
Klaus M. Rodewig
Webserver einrichten und administrieren
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
[email protected] www.galileocomputing.de Galileo Press · Rheinwerkallee 4 · 53227 Bonn
Auf einen Blick 1
Zielsetzung und Planung ....................................................
9
2
Installation und Konfiguration ...........................................
25
3
Systemhärtung ...................................................................
73
4
Serverdienste ......................................................................
103
5
Optimierung und Monitoring .............................................
285
6
Hochverfügbarkeit ..............................................................
353
7
Serverwartung ....................................................................
395
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
978-3-8362-1180-2
© Galileo Press, Bonn 2009 1. Auflage 2009
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 .............................................................................
25 25 30 41 44 44 47 48 49 60 64 65 69
Systemhärtung ......................................................................... 73 3.1
3.2
Inventur benötigter Dienste ......................................................... 3.1.1 Systemstart Ubuntu ......................................................... 3.1.2 Systemstart Gentoo ......................................................... 3.1.3 Abspecken ...................................................................... 3.1.4 Netzwerkdienste kontrollieren ........................................ 3.1.5 Berechtigungen prüfen .................................................... 3.1.6 Virenschutz ..................................................................... Host-Firewall ...............................................................................
73 74 77 80 88 89 91 92 5
Inhalt
3.3 3.4
4
4.2
4.3
4.4
4.5 4.6
Apache ........................................................................................ 4.1.1 Installation ...................................................................... 4.1.2 Konfiguration .................................................................. 4.1.3 SSL .................................................................................. 4.1.4 SSL mit Ubuntu ............................................................... 4.1.5 SSL mit Gentoo ............................................................... 4.1.6 PHP ................................................................................ 4.1.7 Tuning ............................................................................ 4.1.8 Härtung .......................................................................... Datenbanken ............................................................................... 4.2.1 MySQL ............................................................................ 4.2.2 PostgreSQL ..................................................................... Apache Tomcat ............................................................................ 4.3.1 Installation und Konfiguration ......................................... 4.3.2 »mod_jk« – Zusammenarbeit mit dem Webserver ............ 4.3.3 Grundlegende Absicherung ............................................. Jabber .......................................................................................... 4.4.1 Installation unter Ubuntu ................................................ 4.4.2 Installation unter Gentoo ................................................ 4.4.3 Benutzerverwaltung und Client-Konfiguration ................. 4.4.4 Ejabberd mit eigenem SSL-Zertifikat ................................ 4.4.5 Ein eigenes – offizielles – SSL-Zertifikat ............................ Mailversand ................................................................................. Dateitransfer ................................................................................ 4.6.1 FTPS ............................................................................... 4.6.2 SCP und SFTP ..................................................................
103 107 110 132 133 142 144 161 173 176 176 207 230 231 233 239 240 243 247 250 257 259 263 265 266 276
Optimierung und Monitoring .................................................. 285 5.1
6
98 99 99 100 101 101 102
Serverdienste ............................................................................ 103 4.1
5
IDS-Systeme ................................................................................ Rechtliches .................................................................................. 3.4.1 ISO 27001 ...................................................................... 3.4.2 Dokumentation ............................................................... 3.4.3 Änderungsverwaltung ..................................................... 3.4.4 Protokollierung und Monitoring ...................................... 3.4.5 Detaillierte Härtungsmaßnahmen ....................................
Monitoring .................................................................................. 285 5.1.1 SNMP ............................................................................. 286
Inhalt
5.2
6
290 301 334 340 341 342 343 346 348
Hochverfügbarkeit ................................................................... 353 6.1
6.2
6.3
7
5.1.2 MRTG ............................................................................. 5.1.3 Nagios ............................................................................ 5.1.4 Webserver-Statistiken ..................................................... Optimierung ................................................................................ 5.2.1 apachetop ....................................................................... 5.2.2 mytop ............................................................................. 5.2.3 sysstat ............................................................................. 5.2.4 pidstat ............................................................................ 5.2.5 Festplattenstatus .............................................................
Virtualisierung ............................................................................. 6.1.1 Xen – das Konzept .......................................................... 6.1.2 Xen unter Ubuntu ........................................................... 6.1.3 Xen unter Gentoo ........................................................... 6.1.4 Sicherheit ........................................................................ Der Linux-Cluster ......................................................................... 6.2.1 Heartbeat ........................................................................ 6.2.2 Installation und Konfiguration ......................................... 6.2.3 Szenarien ........................................................................ Verteilte Datenhaltung ................................................................ 6.3.1 DRBD ............................................................................. 6.3.2 Installation ...................................................................... 6.3.3 Konfiguration .................................................................. 6.3.4 Integration mit Heartbeat ................................................
354 358 358 365 366 367 368 372 377 382 383 384 385 393
Serverwartung .......................................................................... 395 7.1 7.2
7.3 7.4 7.5
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.
왘
LSB-konforme Distributionen müssen bestimmte Zusatzbibliotheken enthalten (libz, libcurses, libtuil).
왘
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
4 https://www.linux-foundation.org/lsb-cert/productdir.php?by_date
22
Die richtige Distribution
Ubuntu Lifecycle
왘 왘 왘
18 Monate 3 Jahre LTS-Desktop 5 Jahre LTS-Server
Gentoo 왘
keine Versionierung, daher keine Einschränkung
nein
openSUSE 왘
24 Monate
prop. Software
ja
Administration
kostenpflichtiges – Administrationstool »Landscape« erhältlich
YaST2
LSB 3.1
6.06
nein
10.2
Debian
Slackware
SLES
Paketmanager
APT/Debian
Pkgtools
RPM
Typ
binär
binär
binär
Support
왘
Community
왘 왘
Community kostenpflichtig
nein
왘
kostenpflichtige Distribution inkl. Support
Lifecycle
unregelmäßig, ca. 20 Monate
unregelmäßig
5 Jahre
prop. Software
ja
ja
ja
Tools
–
–
YaST2
LSB 3.1
4.0 (Etch)
nein
SLES 9.1
RHEL
Fedora
Mandriva
Paketmanager
RPM
RPM
RPM
Typ
binär
binär
binär
Support
왘
kostenpflichtige Distribution inkl. Support
왘 왘
Community kostenpflichtig
왘 왘
Community kostenpflichtig
Lifecycle
7 Jahre
unregelmäßig
1–3 Jahre
prop. Software
ja
ja
ja
Tools
–
–
DrakConf
LSB 3.1
5
nein
2007.1
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:
"readme.txt" 1899008
Blocks: 3720
IO Block: 4096
reguläre
fe00h/65024d Inode: 3244093 Links: 1 (0700/-rwx------) Uid: (1111/kr) Gid: (1111/kr) 2008-04-04 09:02:32.000000000 +0200 2008-03-26 11:29:36.000000000 +0100 2008-03-26 16:24:40.000000000 +0100
Für ein Verzeichnis sieht die Ausgabe entsprechend anders aus: File: Size: Device: Access: Access: Modify: Change:
"dtest" 4096 Blocks: 8 IO Block: 4096 803h/2051d Inode: 1466339 Links: 2 (0700/drwx------) Uid: (1111/kr) Gid: (1111/kr) 2008-04-06 21:03:35.000000000 +0200 2008-04-06 21:03:35.000000000 +0200 2008-04-06 21:03:35.000000000 +0200
Verzeichnis
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
IBenut. IFrei IBen% Eingehängt auf 231941 2499067 9% / 67 224036 1 % /var/run 3 224100 1 % /var/lock 3008 221095 2 % /proc/bus/usb 3008 221095 2 % /dev 1 224102 1 % /dev/shm 18 224085 1 % /lib/modules/
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 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
… 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
... gelöscht. Sollen auch zu diesem Paket gehörende Konfigurationsdateien gelöscht werden, muss das Paket »gepurged« werden: apt-get purge
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 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 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 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
kr 4096 2008-04-27 14:02 . kr 4096 2008-04-27 13:50 .. kr 399 2008-04-27 14:02 authorized_keys kr 1675 2008-04-27 13:50 id_rsa kr 390 2008-04-27 13:50 id_rsa.pub
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
kr root kr kr kr
kr 4096 2008-05-03 root 4096 2008-04-27 kr 4096 2008-04-27 kr 38806 2008-05-03 kr 220 2008-04-26
20:57 15:35 21:28 20:47 15:16
. .. .adobe .bash_history .bash_logout
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
83
3.1
3
Systemhärtung
/etc/rc2.d/S20openvpn /etc/rc3.d/S20openvpn /etc/rc4.d/S20openvpn /etc/rc5.d/S20openvpn
-> -> -> ->
../init.d/openvpn ../init.d/openvpn ../init.d/openvpn ../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
boot boot boot boot boot
default boot boot default nonetwork boot
boot
85
3.1
3
Systemhärtung
net.eth0 net.lo netmount nscd numlock rmnologin rsyncd slapd slurpd sshd syslog-ng urandom vixie-cron
default boot default
boot
default default boot default
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:
7.0.2 7.0.2(09:09:21 04/30/08)(-debug) http://xorg.freedesktop.org/ X.Org XExt protocol headers
[U] x11-proto/xproto Available versions: Installed versions: Homepage: Description:
7.0.10 ~7.0.12 7.0.7(09:09:08 04/30/08)(-debug) http://xorg.freedesktop.org/ X.Org xproto protocol headers
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 :
… 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
destination
Chain FORWARD (policy ACCEPT) target prot opt source
destination
Chain OUTPUT (policy ACCEPT) target prot opt source
destination
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 Befehle … iptables -F iptables -P INPUT ACCEPT iptables -P OUTPUT ACCEPT
… 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 [...]
108
Apache/2.2.8 (Ubuntu) Feb 2 2008 03:59:12 Magic Number: 20051115:11 APR 1.2.11, APR-Util 1.2.12 APR 1.2.11, APR-Util 1.2.12 32-bit Worker yes (fixed thread count) yes (variable process count) with....
Apache
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
1 http://httpd.apache.org/docs/2.2/mod/directives.html
111
4.1
4
Serverdienste
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
/etc/apache2/mods-enabled/*.load /etc/apache2/mods-enabled/*.conf /etc/apache2/httpd.conf /etc/apache2/ports.conf /etc/apache2/conf.d/ /etc/apache2/sites-enabled/
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 .conf dient zur Konfiguration des betreffenden Moduls, die Datei .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.
3 http://de.wikipedia.org/wiki/Content-Management-System
132
Apache
Abbildung 4.5 Zugangsdaten im Klartext
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
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:
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.
Tabelle 4.2 Sicherheitsrelevante PHP-Direktiven (Forts.)
152
Apache
Direktive
Bedeutung
display_errors
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.
Tabelle 4.2 Sicherheitsrelevante PHP-Direktiven (Forts.)
153
4.1
4
Serverdienste
Direktive
Bedeutung
allow_url_fopen
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.
Tabelle 4.2 Sicherheitsrelevante PHP-Direktiven (Forts.)
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 (