Netzwerk-Verkehr absichern mit SELinux

Fluss-Sperre

Alle großen Distributionen bringen heute Support für SELinux im Kernel mit. Dass sich auch IP-Pakete unter dessen Schutzschild stellen lassen, ist den wenigsten bekannt. Diese Technik eröffnet eine neue Dimension des sicheren Netzwerkens.

Es gibt mehrere Ansätze, auch die Kommunikation im Netz unter den Schutzschirm von SELinux zu stellen. Schon seit der ersten SELinux-Implementierung besteht die Möglichkeit, einzelne Netzwerkobjekte mit einem Security-Context zu versehen. Der Aufruf von »seinfo -c« zeigt alle bekannten SELinux-Objektklassen an, auf einem aktuellen System mehrere Dutzend Objekte, unter anderem auch aus dem Netzwerkbereich. In der SELinux-Policy lassen sich diese nun mit einem Security-Context versehen. Möchte man beispielsweise seine virtuelle Point-to-Point-Netzwerkkarte für Modem-Verbindungen als externe Karte definieren, so gelingt dies mit dem folgenden Eintrag in eine Type-Enforcement-Datei:

netifcon ppp0 system_u:object_r:external_↩
netif_t system_u:object_r:external_packet_t;

Alle Pakete, die nun über die Karte laufen, bekommen den SELinux-Typen »external_packet_t« zugewiesen. Auf die gleiche Art lassen sich weitere Netzwerkobjekte mit einem Security-Context verknüpfen:

portcon tcp 80 system_u:object_r:http↩
_port_t;
nodecon 172.16.0.1 255.255.255.255 system_u:↩
object_r:external_node_t;

Die erste Anweisung versieht den TCP-Port 80 mit einem Label, die zweite Anweisung sorgt dafür das der Rechner mit der Adresse 172.16.0.1 als extern anzusehen ist. Üblicherweise fügt man solche Anweisung entweder mit »semanage« oder über Makroaufrufe dem Regelwerk hinzu. Ein Blick in die Sourcen der SELinux-Reference-Policy [1] hilft hier weiter.

In dem Type-Enforcement Modul für den Webserver kann der Admin dann auf diese Objekte zurückgreifen, um entsprechende Regeln zu definieren:

allow httpd_t external_netif_t : ↩
netif {tcp_send tcp_recv };
allow httpd_t external_node_t : node ↩
{ tcp_send tcp_recv };
allow httpd_t http_port_t : tcp_socket ↩
{ send_msg recv_msg name_bind };

Das erlaubt dem Webserver, sich an den TCP-Port 80 zu binden und mit dem Rechner 172.16.0.1 über das Device »ppp0« zu kommunizieren. Leider besteht jedoch nicht die Möglichkeit, dies in einer einzelnen Regel auszudrücken, stattdessen sind die Anweisungen über mehrere Regeln zu verteilen. Somit ist eine strikte Durchsetzung der einzelnen Anweisungen nicht wirklich möglich.

Pakete labeln mit Netfilter

Seit dem Linux-Kernel 2.6.17 erlaubt die Kombination Netfilter und SELinux, so genanntes Policy-based Packet Filtering umsetzen. Hierbei übernimmt das Netfilter-Framework die Aufgabe, bestimmte IP-Pakete anhand von IPTables-Regeln mit einem Security-Context zu verknüpfen, und SELinux entscheidet anhand von Type-Enforcement-Regeln, ob ein Prozess auf ein IP-Paket mit einem bestimmten Security-Label zugreifen darf oder nicht. Hiermit ist dann auch die strikte Einhaltung von SELinux-Regelsätzen möglich. Netfilter kennt für solche Regeln zwei unterschiedliche Targets, »SECMARK« und »CONNSECMARK« .

Um alle eingehenden und ausgehenden Pakete des Webserver mit einem Label zu versehen, könnte man die Regeln in Listing 1 verwenden.

Listing 1

IPTables-Regeln

iptables -A INPUT -t mangle -p tcp --dport 80 -j SECMARK -selctx http_server_packet_t
iptables -A OUTPUT -t mangle -p tcp --sport 80 -j SECMARK -selctx http_server_packet_t

Hier lässt sich auch schön das Netfilter Conntrack-Modul einsetzen. Um alle Pakete einer bestehenden Verbindung mit dem gleichen Label zu versehen, müsste die zweite Regel wie folgt aussehen:

iptables -A OUTPUT -t mangle -m state --state↩
 RELATED,ESTABLISHED -j CONNSECMARK -restore

In der SELinux-Policy kann der Admin anschließend festlegen, welche Domänen, und somit welche Prozesse, auf dieso so getaggten IP-Pakete zugreifen dürfen:

allow httpd_t http_server_packet_t:packet ↩
{ recv send };

Da üblicherweise der Webserver-Prozess in der Domäne »httpd_t« läuft, hat er Zugriff auf Pakete mit dem Label »http_server_packet_t« .

Dank Netfilter kann der Admin natürlich auch wesentlich fein granulierter einschränken, welche Pakete mit dem Label »http_server_packet_t« zu verknüpfen sind. So lässt sich die Regel beispielsweise nur auf Pakete anwenden, die über eine bestimmte Netzwerkkarte laufen oder die zu einer bestimmten Ziel- oder Absenderaddresse gehören. Ein Blick in die Hilfe-Seiten von Netfilter verrät, welche weiteren Optionen zur Verfügung stehen. Der Aufruf von »seinfo -t | grep packet_t« zeigt an, welche SELinux-Typen für Netzwerk-Pakete es gibt. Nicht aufgeführte Typen könnte man in einer Type-Enforcement-Datei selbst definieren und somit dem System hinzufügen.

Abbildung 1: Mit einer Kombination aus Netfilter und SELinux lässt sich das SELinux-Schutzschild auch auf IP-Pakete anwenden.

In zukünftigen Linux-Kernel Versionen wird speziell für die beiden Targets »SECMARK« und »CONNSECMARK« eine eigene Tabelle mit dem Namen »security« eingeführt [2]. Für das Setzen der Netfilter-Regeln sollte man dann diese, statt der Mangle-Table zu verwenden. Das hat den Vorteil, dass beim Flushen der Standard-Netfilter-Tabellen die Regeln für das Labeling der IP-Pakete erhalten bleiben. Dies hätte zur Folge, dass SELinux anfängt, den Zugriff auf Pakete zu unterbinden, da diese nicht mehr über das notwendige Label verfügen.

Schutz vor gefälschten IP-Paketen

Noch eine Stufe weiter geht eine Implementierung mit dem Namen Labeled Networking. Hierfür existieren zwei unterschiedliche Methoden. Für Systeme die Kompatibilität mit anderen Multi-Level-Security-Systemen (MLS) wie Trusted Solaris oder Trusted HP-UX, benötigen, existiert eine freie Implementierung des Commercial IP Security Option Drafts (CIPSO-2.0). Hierbei handelt es sich um ein Framework bestehend aus einer Protokoll-Engine, einem Kommunikations-Layer und einer Security-Modul-API im Kernel.

Weitaus häufiger in der Praxis anzutreffen ist jedoch die zweite Implementierung von Labeled Networking, auch IPSec-based Labeling" genannt. Mit Hilfe dieser Implementierung ist es möglich, auf Basis der Mandatory-Access-Control eine Entscheidung darüber zu treffen, welcher Prozess auf RechnerX mit welchem Prozess auf RechnerY kommunizieren darf. So lässt sich beispielsweise festlegen, dass der eigene Webbrowser zwar Zugang zum eigenen Intranet-Webserver erhält, nicht aber zu anderen Webservern im eigenen oder externen Netzwerk. Durch die verwendeten IPSec-Protokolle Authentication-Header (AH) und Encapsulated-Security-Payload (ESP) sind außerdem die Authentizität, Integrität und Vertraulichkeit der IP-Pakete sichergestellt. Dies ist gerade in sehr sicherheitskritischen Umgebung wünschenswert.

Abbildung 2: Mit IPSec-based Labeling kann der Admin festlegen, welcher lokale Prozess sich mit welchem entfernten Prozess unterhalten darf.

Bevor auf den Rechnern im vorgestellten Beispiel die SELinux-Konfiguration beginnen kann, ist zuerst das IPSec-System entsprechend zu konfigurieren. Hierfür muss der Admin auf SystemX (172.16.0.100) und SystemY (172.16.0.200) den IKE-Daemon »racoon« [3] konfigurieren. Zur Authentifizierung der beiden Systeme dient der Einfachheit halber ein sogenannter Preshared-Key. Diesen Schlüssel muss der Verwalter auf beiden Systemen in der Datei »/etc/racoon/psk.txt« speichern. In der Racoon-Konfigurationsdatei »/etc/raccon/raccon.conf« richtet er dann die zwei IPSec-Phasen 1 und 2 ein, die zum Aufbau einer Verbindung notwendig sind. Listing 2 zeigt eine beispielhafte Konfiguration für SystemX. Auf der anderen Machine sind die IP-Adressen entsprechend anzupassen, da es sich bei den hier konfigurierten Security-Associations (SA) um jeweils unidirektionale Verbindungen handelt, die in einer sogenannten Security-Association-Database (SAD) gespeichert sind.

Listing 2

<C>/etc/raccon/racoon.conf<C>

### Preshared-Key Datei
path pre_shared_key "/etc/racoon/psk.txt";
# Phase1
remote 172.16.0.200 {
        exchange_mode main;
                proposal {
                encryption_algorithm 3des;
                hash_algorithm md5;
                authentication_method pre_shared_key;
                dh_group 2;
        }
}
# Phase 2
sainfo address 172.16.0.100 any address 172.16.0.200 any {
pfs_group 2;
encryption_algorithm 3des;
authentication_algorithm hmac_md5;
compression_algorithm deflate;
}

Damit Racoon weiß, wann er diese Security-Associations aufbauen soll, muss er vom Kernel dazu aufgefordert werden. Hierzu erzeugt der Admin auf beiden Systemen eine Datei »/etc/setkey.conf« und definiert dort eine so genannte Security-Policy (SP) wie in Listing 3. Auf SystemY muss er die Flussrichtung der IP-Pakete entsprechend umkehren.

Listing 3

<C>/etc/setkey.conf<C>

#!/usr/sbin/setkey -f
# Alle bestehenden Verbindungen löschen
flush;
spdflush;
# Richtlinien zur Verwendung der SAs (172.16.0.100->172.16.0.200)
spdadd 172.16.0.100 172.16.0.200 any
        -ctx 1 1 "system_u:object_r:default_t:s0"
        -P out ipsec esp/tunnel/172.16.0.100-172.16.0.200/require;
# Richtlinien zur Verwendung der SAs (172.16.0.200->172.16.0.100)
spdadd 172.16.0.200 172.16.0.100 any
        -ctx 1 1 "system_u:object_r:default_t:s0"
        -P in ipsec esp/tunnel/172.16.0.200-172.16.0.100/require;

Der Befehl »setkey -f /etc/setkey.conf« lädt die Security-Polices nun in den Kernel und speichert sie in der Security-Policy-Database (SPD). Startet man anschließend Racoon und tauscht Pakete zwischen beiden Rechnern aus, werden die notwendigen Security-Associations aufgebaut und die Pakete fließen durch einen IPSec-Tunnel. Das Security-Label für den IPSec-Socket lässt sich, wie in Listing 3 dargestellt, als Teil der Security-Policies definieren, in diesem Fall »default_t« , im praktischen Betrieb ist natürlich ein anderer Name zu wählen. Zum Testen bietet es sich nun an, Racoon mit »racoon -F« im Vordergrund zu starten, statt auf dessen Init-Skript zurückzugreifen. Somit sieht man direkt alle möglicherweise auftretenden Fehler. Außerdem sind zur initialen Konfiguration die Systeme mittels »setenforce 0« in den Permissive-Mode versetzen, anderenfalls wäre es gar nicht möglich, den lokalen IPSec-Socket mit einem Security-Label zu versehen, da es keine SELinux-Regel gibt, die der SELinux-Domäne der Shell (»staff_t« ) des aufrufenden Benutzers, einen Zugang zu der Domäne des lokalen IPSec-Sockets (»default_t« ) ermöglicht. Ein Blick ins Audit-Log bestätigt dies:

type=AVC msg=audit(1226011201.511:835): ↩
avc:  denied  { setcontext } for pid=2154 ↩
comm="setkey" scontext=root:staff_r:staff_t:↩
...

Startet man nun auf SystemX eine Applikation, beispielsweise einen Webbrowser, in der Domäne »staff_mozilla_t« die sich mit einem Webserver in der Domäne »httpd_t« auf SystemY unterhalten soll, findet man im Audit-Log hierfür wieder jede Menge Fehlermeldungen. Beispielsweise ist es dem Webbrowser erst einmal nicht gestattet, auf die Domäne »default_t« der aufgebauten Security-Association zuzugreifen geschweige denn Daten über diesen Kanal zu versenden. Ein weiterer Log-Eintrag zeigt an, dass der Webbrowser auch keine Pakete von einem entfernten Prozess der Domäne »httpd_t« empfangen darf.

Listing 4

<C>/var/log/audit/audit.log<C>

type=AVC msg=audit:(1226011101.511:101): avc:  denied  { setcontext } for
pid=2154 comm="setkey" scontext=root:staff_r:staff_t:s0-s0:c0.c1023
tcontext=system_u:object_r:default_t:s0 tclass=association
type=AVC msg=audit(1226011103.517:111): avc:  denied  { polmatch } for
pid=2230 comm="client" scontext=root:staff_r:staff_mozilla_t:s0-s0:c0.c1023
tcontext=system_u:object_r:default_t:s0 tclass=association
type=AVC msg=audit(1226011106.519:121): avc:  denied  { sendto } for
pid=2255 comm="client" scontext=root:staff_r:staff_mozilla_t:s0-s0:c0.c1023
tcontext=root:staff_r:staff_mozilla_t:s0-s0:c0.c1023 tclass=association
type=AVC msg=audit(1226011109.527:129): avc:  denied  { recvfrom } for
saddr=192.168.0.105 src=3490 daddr=192.168.0.104 dest=45725 netif=eth0
scontext=root:staff_r:staff_mozilla_t:s0-s0:c0.c1023
tcontext=root:system_r:httpd_t:s0-s0:c0.c1023 tclass=association

Liefen die Maschinen im Enforcing-Mode, wäre eine Kommunikation zwischen den beiden Prozessen nicht möglich. Anhand dieser Log-Einträge lässt sich nun mittels »audit2allow« eine neue SELinux-Policy mit den Regeln erzeugen, die den Zugriff erlauben. Der passende Aufruf von »audit2allow« sieht wie folgt aus:

cat /var/log/audit/audit.log|audit2allow ↩
-l -M selinux_net

Der Aufruf erzeugt ein binäres Policy-Modul »selinux_net.pp« und eine Klartext-Version des Moduls. Diese ist ebenfalls gut zu verwahren, falls später einmal Änderungen oder Erweiterungen an dem Modul nätig werden. Diese Type-Enforcement-Datei hat den Namen »selinux_net.te« und liegt ebenfalls im aktuellen Verzeichnis (Listing 5).

Listing 5

<C>selinux_net.te<C>

module selinux_net 1.1;
require {
    class association { polmatch recvfrom sendto setcontext };
    type default_t;
    type httpd_t;
    type staff_mozilla_t;
    type staff_t;
    role staff_r;
    role system_r;
};
allow staff_t default_t:association setcontext;
allow staff_mozilla_t default_t:association polmatch;
allow staff_mozilla_t self:association sendto;
allow staff_mozilla_t httpd_t:association recvfrom;

Gut sind hier die zu den obigen Deny-Meldungen des Logs korrespondierenden Allow-Anweisungen wie »polmatch« erkennen. Natürlich ist auf dem SystemY, auf dem der Webserver läuft, ebenfalls ein entsprechendes Policy-Modul auf die gleiche Weise zu erzeugen. Der Befehl »semodule -i selinux_net.pp« lädt die Module dann in den MAC-Security-Server des Kernels. Abschließend versetzt »setenforce 1« das System wieder in den Enforcing-Mode, um tatsächlich nur die Zugriffe zu erlauben, die durch SELinux-Regeln gestattet sind.

Für einen einfachen Test kann man auf SystemY einen zweiten Webserver in einer anderen Domäne als »httpd_t« starten. Der Versuch von SystemX mit dem Webbrowser auf diesen Server zuzugreifen, schlägt dann fehl, da eine entsprechende SELinux-Regel fehlt.

comments powered by Disqus

Artikel der Woche

Rechneranalyse mit Microsoft-Sysinternals-Tools

Der Rechner verhält sich eigenartig oder Sie haben eine unbekannte Applikation im Task Manager entdeckt und möchten erfahren, worum es sich dabei genau handelt und ob sie möglicherweise gefährlich ist? In so einem Fall helfen die Sysinternals-Tools von Microsoft. Dieser Beitrag stellt die drei Werkzeuge Autoruns, Process Explorer und TCPView vor. (mehr)
Einmal pro Woche aktuelle News, kostenlose Artikel und nützliche ADMIN-Tipps.
Ich habe die Datenschutzerklärung gelesen und bin einverstanden.

Konfigurationsmanagement

Ich konfiguriere meine Server

  • von Hand
  • mit eigenen Skripts
  • mit Puppet
  • mit Ansible
  • mit Saltstack
  • mit Chef
  • mit CFengine
  • mit dem Nix-System
  • mit Containern
  • mit anderer Konfigurationsmanagement-Software

Google+

Ausgabe /2018