Eingesperrt

Die umfassende Vernetzung macht es zunehmend schwieriger, die Sicherheit einzelner Dienste zu gewährleisten und die Vertraulichkeit der Daten der Benutzer sicherzustellen. FreeBSD bietet mit Jails einen eleganten Ansatz, dieses Dilemma in den Griff zu bekommen.

vorlesen Druckansicht 16 Kommentare lesen
Lesezeit: 11 Min.
Von
  • Christoph Herrmann
Inhaltsverzeichnis

Unter Unix ist die Rechtevergabe einfach und effizient: Es gibt normale Benutzer und root - oder wie auch immer der mit der UID ‘0’ heißt. Bei sämtlichen Veränderungen am System prüft der Kernel, ob der ausführende Prozess mit der UID 0 läuft. Wenn ja, darf er die Änderung durchführen, sonst nicht. Dieses System stößt in komplexeren Umgebungen schnell an seine Grenzen. Es ist schwierig, einzelne administrative Aufgaben zu delegieren, ohne alle Privilegien abzugeben.

Ein einfacher Ansatz, dieses Dilemma zu lösen, ist die Verwendung von sudo. Aber für einen Internet- oder Application-Service-Provider, der viele Kunden auf dem gleichen Rechner arbeiten lässt und für alle Kunden die Vertraulichkeit ihrer Daten sicherstellen muss, ist es mit herkömmlichen Mitteln faktisch unmöglich, einzelne administrative Aufgaben an seine Kunden abzugeben, ohne das ganze System zu kompromittieren. Gerade für diese Anbieter ist es aber notwendig, beispielsweise die Benutzerverwaltung und das Installieren einzelner Dienste oder Programme an die Kunden zu übergeben.

Auch für das Design eines Firewall ist es von Interesse, einzelne Proxies und Dienste in der DMZ (Demilitarisierte Zone) so voneinander zu trennen, dass eine Schwachstelle in einem Dienst (oder allgemeiner das Hacken eines Dienstes) nicht den gesamten Rechner kompromittiert und der Eindringling mit den gewonnenen Privilegien möglichst wenig anfangen kann.

Traditionell benutzt man auf Unix-Systemen chroot, um den Zugriff einzelner Prozesse auf einen Teil der Verzeichnisstruktur eines Rechners zu begrenzen. Auch dieses Vorgehen, das speziell FTP- und Webservern verwenden, bietet aber nur eine sehr begrenzte Sicherheit. Erlangt ein Angreifer innerhalb einer chroot-Umgebung Root-Rechte bereitet es ihm keine ernsthaften Schwierigkeiten, diese zu verlassen und die Kontrolle über den gesamten Rechner zu erlangen. Historisch betrachtet entstand der chroot-Systemaufruf, bevor es FTP überhaupt gab. Er erlaubte es, in einem Verzeichnis eine neue Version des Betriebssystems kompilieren zu können, ohne mit Header-Dateien oder Bibliotheken der alten in Konflikt zu geraten. Bill Joy hat im März 1982 auf 4.1BSD den chroot-Call implementiert, ftp kam erst Anfang 1983 dazu. Spätestens wenn man versucht, auf einem Rechner verschiedene Dienste in verschiedenen chroot-Umgebungen an verschiedene IP-Adressen zu binden, wächst der Installations- und Verwaltungsaufwand beliebig an.

Ein Jail ist eine Erweiterung des Systemaufrufs chroot, der eine komplette virtuelle Instanz des Betriebssystems in einem Verzeichnis einrichtet. Dies beschränkt nicht nur den Zugriff auf das Dateisystem: Jeder Jail besitzt seine eigene IP-Adresse und nur diese ist innerhalb des Jail sichtbar. Darüber hinaus unterliegt der Prozessraum Beschränkungen. In einem Jail zeigt ps nur die darin laufenden Prozesse; diese können nur mit Prozessen in dieser Umgebung über Signale oder per IPC kommunizieren. Lediglich über Sockets kann eine Kommunikation mit anderen Prozessen, sowohl in anderen Jails als auch auf anderen Rechnern, erfolgen. Nicht privilegierte Prozesse bemerken keine Einschränkungen, wenn sie in einem Jail laufen. Für Prozesse die unter der UID 0 laufen, gelten einige andere Restriktionen, die es außerhalb eines Jail nicht gibt:

  • Der laufende Kernel lässt sich nicht modifizieren, beispielsweise durch Laden von Modulen oder Ändern von Parametern via sysctl.
  • Die Netzparameter wie Interface-Konfiguration, IP-Nummern oder Routing-Einträge sind unveränderlich.
  • Ein Mounten oder Aushängen von Dateisystemen funktioniert nicht.
  • Das Anlegen von Gerätedateien ist verboten.
  • Es ist nicht möglich, Netzressourcen zu assoziieren, die dem Jail nicht zugeordnet sind, insbesondere existiert kein Zugriff auf Raw-IP-Sockets.
  • Sicherheitsrelevante Flags einer Datei sind nur lesbar.

Diese Einschränkungen stellen sicher, dass es selbst Root nicht gelingt, aus einem Jail auszubrechen. Ein etwaiger Hacker kann einen Jail nur bedingt für weitere Aktionen nutzen und von dort auch mit Sniffern nicht im Netz horchen.

Andererseits besitzt Root in einem Jail den vollen Zugriff auf das Filesystem (im Jail), kann Dateien anlegen, löschen, Eigentümer und Gruppe ändern und so weiter. Root (in einem Jail) darf Signale an alle Prozesse in diesem Jail senden, darf Benutzer anlegen und löschen, Software installieren und auch an privilegierte Ports binden. Damit kann er beispielsweise beliebige Internetdienste in diesem Jail aufsetzen.

Ein Administrator eines Systems gibt die Kontrolle über die Maschine nicht aus der Hand, wenn er anderen Leuten das Root-Passwort eines Jail auf dieser Maschine aushändigt. Wird ein Jail gehackt, in dem ein Applikation-Level-Gateway läuft, betrifft dies vor allem diesen Proxy, bedeutet aber nicht unmittelbar ‘Gefahr im Verzug’.

Im Gegensatz zu virtuellen Umgebungen wie VMware läuft für einen Jail kein eigener Prozess. Die einzelnen Prozesse sind nur als in einem Jail laufend gekennzeichnet, dass heißt, die Verwendung von Jails erzeugt keine zusätzliche Last auf dem Rechner. Es gibt ISPs, die viele hundert Jails auf einem Server betreiben.

Ein Beispiel soll das Handling von Jails verdeutlichen. Dabei bezeichnet Jail-Environment die Umgebung im Jail und Host-Environment das Betriebsystem der zugrunde liegenden Maschine. Der Jail wird im Verzeichnis /myjail installiert, hat die IP-Adresse 10.11.12.123 und den Hostnamen ‘mytestjail’.

Vor dem Einrichten des Jail-Environment muss der Administrator auf dem Host-Environment einige Vorbereitungen treffen: Er muss einem Netzinterface direkt oder über einen IP-Alias die IP-Nummer des Jail zuweisen.

ifconfig ed0 inet alias 10.11.12.123 netmask 255.255.255.255

Darüber hinaus sind auf dem Hostsystem alle Netzdienste so zu konfigurieren, dass sie sich nur an die IP-Adresse des Hostsystems und nicht an die eines Jail binden (inetd, sshd) oder ohne Netz arbeiten (syslogd). Dienste, bei denen das nicht möglich ist, sind abzuschalten (sendmail, portmap/rpcbind).

Läuft auf dem Hostsystem ein Prozess, der sich an alle IP-Adressen bindet, scheint dieser Dienst aus allen Jails heraus angeboten zu werden. Auf dem Hostsystem sind ja alle IP-Nummern zu sehen, auch die aller Jails. Läuft beispielsweise auf dem Hostsystem ein sendmail, dann lauscht dieser an Port 25 - für alle IP-Adressen des Hostsystems. Kontaktiert jemand Port 25 einer IP-Adresse, die zu einem Jail gehört, in dem kein sendmail läuft, nimmt das sendmail des Hostsystems das Paket an und reagiert darauf. Solche Dienste sollte man zweckmäßigerweise nur in Jails installieren.

Jedes einzelne Jail muss ein ‘FreeBSD-Userland’ - eine Betriebssystemumgebung - bekommen. Der einfachste Ansatz ist, mit dem kompletten Userland zu beginnen und je nach Anforderung alles nicht Benötigte zu löschen. Einen Weg bietet der ‘make world’-Mechanismus:

cd /usr/src; make world DESTDIR=/myjail

Da ein make world die Konfigurationsdateien unter /etc nicht anfasst, muss man diese getrennt in dem Jail installieren.

cd /usr/src/etc; make distribution DESTDIR= /myjail NO_MAKEDEV=yes

Optional lässt sich das Userland aus den entsprechenden Paketen der FreeBSD-Distribution, entweder aus dem Internet oder von einer FreeBSD-CDROM direkt nach /myjail installieren. Bei einer Installation via pkg_create erzeugte Softwarepakete vom Hostsystem in ein Jail ist Vorsicht angesagt: Da die Entwickler diesen Mechanismus noch nicht für die Benutzung mit Jails erweitert haben, löst das Tool eventuelle Abhängigkeiten auf dem Host und nicht im Jail auf. Innerhalb der Jails selbst arbeiten sowohl die Ports als auch der pkg_*-Mechanismus wie gewohnt.

Danach sind in /myjail/dev die entsprechenden Device-Dateien anzulegen. Dies erledigt das MAKEDEV-Skript cd /myjail/etc; sh MAKEDEV jail. Der Aufruf cd /myjail; ln -sf dev/null kernel, das Anlegen einer leeren fstab, das Setzen des Root-Passworts sowie unter Umständen das Einrichten von Benutzern und der im Jail verfügbaren Dienste vervollständigen die Jail-Konfiguration.

Das Einrichten eines Jail entspricht voll und ganz dem eines FreeBSD-Rechners. Ein einfacher Weg zur Konfiguration ist der Aufruf von /stand/sysinstall im jeweiligen Jail. Dazu muss der Administrator das sysinstall-Binary in den Jail kopieren:

mkdir /myjail/standcp /stand/sysinstall /myjail/stand

Danach darf man ihn via jail /myjail mytestjail 10.11.12.123 /bin/sh starten und landet in einer im Jail laufenden Shell. Hier startet der Aufruf /stand/sysinstall die weitere Konfiguration. Hat man diese vollständig durchgeführt, lässt sich der Jail in Betrieb nehmen:

mount -t procfs proc /myjail/proc
jail /myjail mytestjail 10.11.12.123 /bin/sh /etc/rc

Läuft im Jail ein sshd und ist dieser für den externen Rootzugang konfiguriert, kann sich der Superuser via SSH einloggen, um andere Dienste einzurichten oder Verwaltungsaufgaben zu erledigen.

Zur Zeit lässt sich ein Jail leider nur schlecht aus dem Host-Environment heraus administrieren. Da er über keine Konsole verfügt, lässt er sich nicht direkt sondern nur über das Netz verwalten. Insbesondere ist es nicht möglich, aus der Hostumgebung heraus Prozesse innerhalb eines Jail zu starten. Prozesse die in einem Jail laufen, tauchen in der Ausgabe von ps oder top mit einem ‘J’ markiert auf. Man kann sie im Host-Environment nicht nur erkennen, sondern ihnen von dort auch Signale senden. Da aus dem Host-Environment heraus voller Zugriff auf das Dateisystem des Jail besteht, kann Root durchaus Software von außerhalb in einen Jail einspielen. Die Standardkommandos zum Herunterfahren einer Maschine (halt(8), reboot(8), shutdown(8)) funktionieren in einem Jail ebenfalls nicht. Um einen Jail herunterzufahren, muss man alle Prozesse in diesem Jail beenden. Gerade wenn mehrere Jails auf einem Rechner laufen, gestaltet sich dies aus der Hostumgebung heraus unter Umständen schwierig. Der einfachere Weg ist, sich in dem Jail einzuloggen und als Root ein kill -TERM -1 oder kill -KILL -1 auszuführen.

Da jeder Jail seine eigene User-Verwaltung besitzt, kann die Umsetzung der UIDs auf echte Benutzer und umgekehrt auf einem Rechner mit vielen Jails durchaus zu Verwirrungen führen. Dieses Problem sollte dem Administrator des Host-Environmentes bewusst sein.

Christoph Herrmann
ist Dipl.-Physiker und arbeitet für die science + computing ag in Berlin. Er ist spezialisiert auf den Betrieb großer, heterogener Unix-Netze.
(avr)