Mit einer vernünftigen Backup-Strategie wappnen sich Administratoren erfolgreich gegen Datenverluste und längere Systemausfälle. So zeigen wir Ihnen ... (mehr)

SELinux-Kategorien

Neben dem SELinux Type-Enforcement, das primär dafür dient, den Zugriff von Containern auf das Host-System einzuschränken, unterstützt Docker auch die sogenannte Multi-Category-Security (MCS). Hierbei geht es vor allem darum, Container untereinander abzuschotten und lediglich Zugriff auf die Container-eigenen Ressourcen zu ermöglichen, aber nicht auf Ressourcen eines anderen Containers zurückgreifen zu können. Die bereits beim Libvirt-Framework eingesetzte Technik sVirt weist hierfür jedem Container zwei zufällige Kategorien zu. Ein Zugriff ist nun lediglich auf Objekte möglich, die ebenfalls über diese beiden Kategorien verfügen. Die Kategorien sind dabei Teil des SELinux-Labels und der Docker-Service kümmert sich darum, sämtliche Objekte, die zu einem Container gehören, mit diesen Kategorien zu versehen. Container-Prozesse bekommen diese Kategorien natürlich ebenfalls dynamisch beim Starten zugewiesen.

Innerhalb eines Container haben sämtliche Ressourcen diese Kategorien zugeordnet bekommen und ein Zugriff ist somit problemlos möglich:

# ps -efZ
LABEL: system_u:system_r:svirt_ lxc_net_t:s0:c868,c981
UID: root
PID: 1
 PPID: 0
C: 0
STIME: 14:25
TTY: ?
TIME: 00:00:00
CMD: /bin/bash
 
# ls -lZ /etc/shadow
----------. root root system_u:object_r:svirt_sandbox_file_t:s0:c868,c981 /etc/shadow
 
# cat /etc/shadow > /dev/null ; echo $?
0

Würde der Zugriff auf Ressourcen mit einer anderen Kategorie erfolgen, schlüge dieser fehl. Hierfür wieder ein Beispiel: Zwei Dateien verfügen über das gleiche SELinux-Label svirt_sandbox_file_t. Wir haben soeben gesehen, dass Container auf Objekte von diesem Typen zugreifen können. Da die Datei »/tmp/shadow-container1« aber zu einem anderen Container gehört als die Datei »/tmp/shadow-container2« , verfügen diese jeweils über unterschiedliche Kategorien:

# ls -lZ /tmp/shadow-container*
-rw-r--r--. root root unconfined_u:object_r:svirt_sandbox_file_t:s0:c868,c981 /tmp/shadow-container1
-rw-r--r--. root root unconfined_u:object_r:svirt_sandbox_file_t:s0:c111,c323 /tmp/shadow-container2

Der Container1 läuft in der SELinux-Domäne svirt_lxc_net_t und hat die Kategorien c868 und c981 zugewiesen bekommen. Mittels »runcon« wird der Zugriff wieder entsprechend simuliert:

# runcon system_u:system_r:svirt_lxc_net_t:s0:c868,c981 cat /tmp/shadow-container1
shadow container 1
# runcon system_u:system_r:svirt_lxc_net_t:s0:c868,c981 cat /tmp/shadow-container2

 

cat: /tmp/shadow-container2: Permission denied

Würde der Zugriff auf die Datei »/tmp/shadow-container2« von einem Prozess mit dem SELinux-Label system_u:system_r:svirt_lxc_net_t:s0:c111,c323 erfolgen, so wäre dieser erfolgreich und das Auslesen der Datei »/tmp/shadow-container1« würde in diesem Falle fehlschlagen.

Eigene SELinux-Domäne

Innerhalb eines Containers laufen alle Prozesse innerhalb der Domäne svirt_lxc_net_t. Dieser Domäne ist es gestattet, sich an jeden beliebigen Netzwerkport zu binden. Dies ist weniger restriktiv, als wenn ein Netzwerkdienst auf dem Host laufen würde, da dort ganz klar definiert ist, an welchen Port sich dieser binden kann:

# semanage port -l |grep smtp
smtp_port_t tcp 25, 465, 587
# sesearch --allow -s postfix_master_t -t smtp_port_t -p name_bind allow postfix_master_t smtp_port_t : tcp_socket name_bind ;

Seit der Docker-Version 1.3 ist es nun möglich, die SELinux-Domäne, in der Container-Prozesse ablaufen, beim Starten des Containers selbst zu definieren. Notwendig ist hierfür jedoch ein eigenes Policy-Modul, das zuvor in den Security-Server des Kernels geladen werden muss. Dieses Policy-Modul muss die neue SELinux-Domäne definieren und festlegen, welche Rechte diese Domäne und somit die Prozesse, die in dieser ablaufen, erhalten sollen.

Listing 1 zeigt ein Beispiel für ein solches Policy-Modul, das dafür sorgt, dass Postfix-Prozesse innerhalb eines Containers in der Domäne docker_postfix_t ablaufen und sich nur an den Netzwerkport binden können, der in der Policy definiert wurde. Hier also smtp_port_t, was den Ports 25, 465, 587 entspricht.

Listing 1: Policy-Modul docker_postfix.te



policy_module(docker_postfix,1.0)
virt_sandbox_domain_template(docker_postfix)
allow docker_postfix_t self: capability { chown dac_override kill setgid
setuid net_bind_service sys_chroot sys_nice sys_tty_config } ;
allow docker_postfix_t self:tcp_socket create_stream_socket_perms;
allow docker_postfix_t self:udp_socket create_socket_perms;
corenet_tcp_bind_all_nodes(docker_postfix_t)
corenet_tcp_bind_smtp_port(docker_postfix_t)
corenet_udp_bind_all_nodes(docker_postfix_t)
corenet_udp_bind_smtp_port(docker_postfix_t)
sysnet_dns_name_resolve(docker_postfix_t)
permissive docker_postfix_t;

Nach der Installation des Pakets selinux-policy-devel können Sie dieses Modul in eine binäre Version übersetzen, bevor Sie es anschließend in den Security-Server laden (Listing 2).

Listing 2: Laden des Moduls in den Security-Server



# make -f /usr/share/selinux/devel/Makefile docker_postfix.pp
Compiling targeted docker-postfix module
/usr/bin/checkmodule: loading policy configuration from
tmp/docker-postfix.tmp
/usr/bin/checkmodule: policy configuration loaded
/usr/bin/checkmodule: writing binary representation (version 17) to
tmp/docker-postfix.mod
Creating targeted docker-postfix.pp policy package
rm tmp/docker-postfix.mod.fc tmp/docker-postfix.mod
# semodule -i docker_postfix.pp

Schließlich starten Sie den Container, in dem der Postfix-Service laufen soll, mit den folgenden Kommandos:

# docker run fedora:postfix --security-opt label:type: docker_postfix_t postfix start

Um sicherzustellen, dass der Postfix-Server alle notwendigen Zugriffsrechte bekommt, sollten Sie im Anschluss das Audit-Log überwachen und eventuell fehlende Rechte dem Policy-Modul hinzufügen. Hierfür können Sie auf das Tool audit2allow zurückgreifen:

# grep docker_postfix_t /var/log/audit/audit.log | audit2allow > docker_postfix.te

Anschließend erhöhen Sie die Versionsnummer in der Type Enforcement-Datei, übersetzen das Modul wie oben gezeigt und laden es mit »semodule -u docker_postfix.pp« erneut in den Security-Server. Wenn Sie sicher sind, dass der Postfix-Service ohne Probleme funktioniert, können Sie auch die permissive Anweisung aus dem Modul entfernen und somit sicherstellen, dass der Kernel die im Modul definierten Regeln auch tatsächlich umsetzt.

Ähnliche Artikel

comments powered by Disqus
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

Ausgabe /2023