Systemd/SELinux Refresher
1 Agenda
- Vorbereitung der Lab-Umgebung
- Systemd-Refresh
- Namespaces mit systemd-nspawn
- SELinux Refresh
- Fehlersuche
2 Lab-Umgebung Internet
- Benutzername:
user - Passwort:
network - Maschinen im Internet
| Nummer | Name | URL | |
|---|---|---|---|
| 1 | Carsten | https://selinux001.linux-sicherheit.org | |
| 2 | Ohlmann | https://selinux002.linux-sicherheit.org | |
| 3 | Eggers | https://selinux003.linux-sicherheit.org | |
| 4 | Maier | https://selinux004.linux-sicherheit.org | |
| 5 | Jander | https://selinux005.linux-sicherheit.org | |
| 6 | Hannemann Alex | https://selinux006.linux-sicherheit.org | |
| 7 | Hannemann Andreas | https://selinux007.linux-sicherheit.org | |
| 8 | Zwick | https://selinux008.linux-sicherheit.org | |
| 9 | Weiss | https://selinux009.linux-sicherheit.org | |
| 10 | Wittmann | https://selinux010.linux-sicherheit.org | |
| 11 | Zielasko | https://selinux011.linux-sicherheit.org | |
| 12 | Gress | https://selinux012.linux-sicherheit.org | |
| 13 | Thanner | https://selinux013.linux-sicherheit.org | |
| 14 | Pratneker | https://selinux014.linux-sicherheit.org | |
| 15 | Schmelzer | https://selinux015.linux-sicherheit.org | |
| 16 | Pfeiffer | https://selinux016.linux-sicherheit.org | |
| 17 | Hartmann | https://selinux017.linux-sicherheit.org | |
| 18 | Kuhn | https://selinux018.linux-sicherheit.org |
3 Vorbereitung der Lab-Umgebung
3.1 Ein einfacher Web-Server
- Wir benutzen einen einfachen Webserver als Beispiel-Dienst für die Systemd- und SELinux Übungen in diesem Kurs
- Hier ist der Quellcode (C Programmiersprache) eines (sehr) einfachen Web-Servers. Dieser Webserver liefert nur eine statische Webseite aus (diese Webseite ist fest im Quellcode des Servers eingebaut und wird nicht aus dem Dateisystem geladen):
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <err.h>
char response[] = "HTTP/1.1 200 OK\r\n"
"Content-Type: text/html; charset=UTF-8\r\n\r\n"
"<!DOCTYPE html><html><head><title>Bye-bye baby bye-bye</title>"
"<style>body { background-color: #111 }"
"h1 { font-size:4cm; text-align: center; color: black;"
" text-shadow: 0 0 2mm red}</style></head>"
"<body><h1>Goodbye, world!</h1></body></html>\r\n";
int main()
{
int one = 1, client_fd;
struct sockaddr_in svr_addr, cli_addr;
socklen_t sin_len = sizeof(cli_addr);
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0)
err(1, "can't open socket");
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(int));
int port = 8080;
svr_addr.sin_family = AF_INET;
svr_addr.sin_addr.s_addr = INADDR_ANY;
svr_addr.sin_port = htons(port);
if (bind(sock, (struct sockaddr *) &svr_addr, sizeof(svr_addr)) == -1) {
close(sock);
err(1, "Can't bind");
}
listen(sock, 5);
while (1) {
client_fd = accept(sock, (struct sockaddr *) &cli_addr, &sin_len);
printf("got connection\n");
if (client_fd == -1) {
perror("Can't accept");
continue;
}
write(client_fd, response, sizeof(response) - 1); /*-1:'\0'*/
close(client_fd);
}
}
3.2 Übung
- Erstelle ein neues Verzeichnis für unser Project und erstellen die Datei mit dem Quellcode des Webserver (oben) mit Hilfe eines Text-Editors (emacs, mg, nano, vim etc)
mkdir ~/src cd ~/src $EDITOR simple-server1.c
- C-Compiler installieren
# dnf install gcc
- Übersetze den Quellcode in eine Programm-Datei
(
simple-server)
gcc -o simple-server simple-server1.c
- Die Programmdatei in das Verzeichnis
/usr/local/binkopieren
cp simple-server /usr/local/bin
- Wir starten den Server im Hintergrund und testen die Funktion in dem wir uns mit einem Web-Browser an Port 8080 verbinden. Wir sollten dort eine "Hello^H^H^H^H^HGoodbye World" Meldung sehen. Bei jeder Verbindung gibt der Server den Text Got connection aus.
simple-server &
4 Systemd-Refresh
- Systemd ist das Systemd zum Verwalten von Diensten auf aktuellen Linux-Systemen.
- Systemd kann
- Dienste starten
- Dienste stoppen
- Dienste an- und ausschalten
- Dienste blocken (Start verhindern)
- Abhängigkeiten zwischen den Diensten definieren
- Dienste automatisch neu starten
- Log-Daten in einer Datenbank verwalten (Journal)
- Hostname, Systemzeit, Netzwerk und Namensauflösung verwalten
- Systemd Dokumentation und Informationen https://www.freedesktop.org/wiki/Software/systemd/
4.1 Übungen
- Die nachfolgenden Befehle sollten auf den Lab-Systemen ausprobiert
werden. Einige Befehle sollten an das System angepasst werden, so
sollte
dienst.servicedurch einen auf dem System laufenden Dienst (z.B.rngd.service) ersetzt werden. - Die Übungen müssen als Benutzer
rootausgeführt werden (Befehlsudo -i) - Die Lab-Systeme dürfen auch neu gestartet werden
4.2 Systemd Architektur
| Daeamon | Verwaltungs-Tool |
|---|---|
| systemd | systemctl |
| systemd-hostnamed | hostnamectl |
| systemd-machined | machinectl |
| systemd-journald | journalctl |
| systemd-localed | localectl |
| systemd-logind | loginctl |
| systemd-shutdownd | shutdown |
| systemd-timedated | timedatectl |
4.3 Systemd Unit Arten
| service | von Systemd gestartete Dienste und Anwendungen |
| socket | Socket Aktivierung |
| scopes | Gruppierung von gestarteten Anwendungen |
| slice | Resourcen für Prozessgruppen |
| path | Pfad Aktivierung |
| mount | Mountpoints (teilweise aus /etc/fstab) |
| automount | automatische Mountpoints |
| target | Gruppen von Units |
4.4 Standard Konfigurationsdateien
Systemd definiert eine Reihe von Standard-Konfigurationsdateien, welche distributions-übergreifend verfügbar sind
/etc/hostname |
Hostname |
/etc/machine-id |
Statistisch eindeutige ID des Rechners (UUID) |
/etc/os-release |
Informationen ueber das Betriebssystem (Distribution, Versionsnummer) |
/etc/locales.conf |
Ländereinstellungn |
/etc/vconsole.conf |
Einstellungen der Text-Konsolen |
/etc/modules-load.d/*.conf |
Konfiguration der Kernel-Module |
/etc/sysctl.d/*.conf |
Konfigurationseinstellungen fuer Kernel-Parameter |
/etc/tmpfiles.d/*.conf |
Konfiguration fuer Verzeichnisse mit temporären Dateien |
/etc/binfmt.d/*.conf |
Konfiguration fuer Linux-fremde Programmformate |
4.5 Systemd Konfigurationsdateien
- Der Befehl
systemd-deltazeigt die Änderungen an System-Konfigurationsdateien.
4.5.1 System-Konfigurationen
/etc/systemd/... |
(hoechste System Prio) |
/run/systemd/... |
(zweite Prio) |
/usr/lib/systemd/... |
(dritte System Prio) |
/usr/lib/systemd/system-preset... |
(letzte System Prio) |
4.5.2 Benutzer-Konfigurationen
$XDG_CONFIG_HOME/systemd/user/* |
(hoechste User Prio) |
$HOME/.config/systemd/user/* |
|
/etc/systemd/user/* |
|
$XDG_RUNTIME_DIR/systemd/user/* |
|
/run/systemd/user/* |
|
$XDG_DATA_HOME/systemd/user/* |
|
$HOME/.local/share/systemd/user/* |
|
/usr/lib/systemd/user/* |
(unterste User Prio) |
4.6 Systemd-Units anzeigen und editieren, Drop-Ins
- lesbarer Status eines Systemd-Dienstes inkl. Pfad zu der Unit-Datei und ggf. Drop-Ins
- Alle Systemd-Einstellungen (inkl. der Defaults) einer Unit anzeigen. Dieser Befehl kann gut in Skripten benutzt werden.
systemctl show <unit>
4.6.1 Systemd-Units editieren
- Einige Einstellungen einer vom System mitgelieferten Unit
überschreiben. Es wird eine Drop-In Datei in
/etc/systemd/systemd/<unit-name>.<unit-typ>.d/override.conferstellt. Beim Ändern von Unit-Dateien persystemctl editwird der Systemd-Dämon direkt nach dem Beenden des Editors über die Änderungen informiert.
systemctl edit <unit-name>
- Die vom System gelieferte Unit in
/etc/systemd/system/kopieren und komplett ersetzen
systemctl edit --full <unit-name>
- Temporäre Änderungen an den vom System mitgelieferten Units
systemctl edit --runtime <unit-name>
4.7 Systemd-Dienste
4.7.1 Dienste starten und eintragen
- Dienst starten
systemctl start dienstname
- Alternativ wird der
serviceBefehl auch noch unterstützt
service dienst start
- den aktuellen Status eines Dienstes anzeigen
systemctl status dienst
- Dienst anschalten, so das der Dienst bei einem Rechnerneustart mit gestartet wird
systemctl enable dienst systemctl reenable dienst
- Dienst anschalten und gleich starten
systemctl enable --now dienst
- Dienst neu starten.
try-restartstartet den Dienst nur, wenn der Dienst schon gestartet war
systemctl restart dienst systemctl try-restart dienst
- Dienst neu laden (reconfig)
systemctl reload dienst
- Dienst sofort, einmalig beenden
systemctl stop dienst
- Alternativ: Beenden eines Dienstes mit
service
service dienst stop
- Dienst beim Booten nicht starten
systemctl disable dienst
- Dienst "maskieren" und "de-maskieren". Ein maskierter Dienst kann nicht automatisch (als Abhängigkeit) oder manuell gestartet werden
systemctl mask name systemctl unmask name
- Dienstkonfiguration erweitern/anpassen (Override-Datei anlegen/editieren)
systemctl edit dienst
4.7.2 Systemd Aufgabe – eigener Dienst
date-daemon– schreibt Datum / Uhrzeit alle 60 Sekunden in syslog- die Datei
/usr/local/bin/datedmit einem Texteditor erstellen
#!/bin/sh while true; do logger -t dated $(date) sleep 60 done
- Datei als ausführbares Programm markieren:
chmod +x /usr/local/bin/dated
- Ein weiteres Terminal-Fenster öffnen, dort den Systemlog
(
/var/log/messages) anzeigen mittail -f <datei>oderlessim "Follow" Modus (Taste "F") - Das Programm
datedauf der Kommandozeile im Terminal ausführen, prüfen das die Uhrzeit jede Minute in das Syslog geschrieben wird - Das Programm
datedabbrechen - Eine Dienstekonfiguration für den neuen "dated" Dienst in der Datei
/etc/systemd/system/dated.serviceerstellen
[Unit] Description=Logged Datum/Uhrzeit alle 60 Sekunden in Syslog After=syslog.target [Service] ExecStart=/usr/local/bin/dated [Install] WantedBy=multi-user.target
- Dem
systemdInit-Prozess den neuen Dienst mitteilen
systemctl daemon-reload
- den neuen Dienst starten
systemctl start dated
- Prüfen, ob der "dated" Dienst laüft (Einträge im Syslog
/var/log/messagesund Systemd-Journal), Prozess prüfen mitps - Dienst-Status prüfen
systemctl status dated
- Dienst stoppen, prüfen das der Dienst wirklich gestoppt ist (keine
neuen Einträge im Syslog), Prozess in der
psAusgabe verschwunden - Dienst anschalten, so das
datedbei einem Systemneustart auch gestartet wird
systemctl enable dated
- Prüfe, ob der
datedDienst bei einem Reboot des Systems wirklich gestartet wurde. Wenn nicht, warum nicht?
4.7.3 Dienste anzeigen
- alle aktiven Service-Units anzeigen
# systemctl list-units -t service
- auch inaktiven Service-Units anzeigen
# systemctl list-units -t service --all
- alle Unit-Dateien zu Diensten (Services) anzeigen
# systemctl list-unit-files -t service
- Alle Sockets- und Timer-Units auflisten
# systemctl list-sockets # systemctl list-timers
4.7.4 Abfrage, ob ein Dienst angeschaltet und/oder aktiv ist
# systemctl is-enabled name.service # systemctl is-active name.service
4.7.5 Dienst-Abhängigkeiten
- die Abhängigkeiten eines Dienstes anzeigen
systemctl list-dependencies <unit>
- Units anzeigen, welche von diesem Dienst abhängen
systemctl list-depedencies --reverse <unit>
4.8 Systemd-Targets
4.8.1 Targets auflisten
- Mittels Systemd können Gruppen von Diensten zu Systemzuständen (Targets) zusammengefasst werden. Targets definieren, welche Dienste gestartet und nicht gestartet sein sollen
# systemctl --type=target --all
4.8.2 Target ansteuern
# systemctl isolate rescue.target
4.8.3 Rescue-/Emergency-Mode (Single-User)
- Linux in den Rettungs-Modus versetzen. Achtung, in diesem Modus ist kein Netzwerk verfügbar, dieser Modus sollte daher nur bei Zugriff auf eine Admin-Konsole (direkt an der Maschine oder per KVM-Switch) ausgeführt werden. Diese Befehle nicht auf der Lab-Umgebung ausführen!
# systemctl rescue # systemctl emergency
4.8.4 Rechner anhalten/herunterfahren
# systemctl halt # systemctl poweroff # systemctl reboot
4.8.5 Standard-Boot-Target
- Das Standard-Boot-Target anzeigen
# systemctl get-default # readlink /etc/systemd/system/default.target
- Das Standard-Boot-Target ändern
systemctl set-default graphical.target
4.9 Analyse des Systemd-Bootvorgangs
- Start-Units nach Zeitverbrauch anzeigen
# systemd-analyze blame
- Den kritischen Pfad des Boot-Prozesses anzeigen
# systemd-analyze critical-chain
- Boot-Prozesse grafisch anzeigen
- Übung: wie kann die Datei
startup.svgbei einer entfernten Maschine angezeigt werden? Überlege, wie Du die Datei anzeigen kannst.
# systemd-analyze plot > startup.svg
4.10 Systemd Resource-Management und CGroups
- Man-Page
SYSTEMD.RESOURCE-CONTROL(5)
4.10.1 Unit Parameter
| Parameter | Default | Beschreibung |
|---|---|---|
| CPUAccounting=true | -- | CPUAccounting anschalten |
| CPUQuota=xx% | 100%*CPU | CPU Verbrauch festlegen |
| CPUShares=value | 1024 | CPU Belegung |
| MemoryAccounting=true | -- | Speicherverbrauch Ueberwachung anschalten |
| MemoryLimit=value | -- | Speicherverbrauch (K,M,G,T) |
| BlockIOAccounting=true | -- | BlockIO Accounting anschalten |
| BlockIOWeight=value | 1000 | generische IO Prio (100 < Wert < 1000) |
| BlockIODeviceWeight=device_name value | 1000 | IO Prio fuer Geraet |
| BlockIOReadBandwidth=device_name value | -- | Lese-Bandbreite pro Sekunde (K,M,G,T) |
| BlockIOWriteBandwidth=device_name value | -- | Schreib-Bandbreite pro Sekunde (K,M,G,T) |
| DeviceAllow=device_name options | -- | Zugriff (r,w,m) auf Geraete-Dateien |
| DevicePolicy=value | -- | Zugriffs-Policy fuer Geraete-Dateien (strict, closed, auto) |
| Slice=slice_name | -- | Unit einem Slice zuordnen |
| ControlGroupAttribute=attribute value | -- | Low-Level Control-Group Parameter setzen |
4.10.2 Exec Parameter (im Abschnitt [Service])
| Nice= | den nice Wert des Prozesses setzen |
| OOMScoreAdjust= | den Score Wert des Kernel Out-of-Memory (OOM) Killers im Kernel für dieses Prozess setzen |
| IOSchedulingClass=, IOSchedulingPriority= | die IO-Priorität des Prozesses setzen |
| CPUSchedulingPolicy=, CPUSchedulingPriority= | die CPU-Priorität des Prozesses setzen |
| CPUAffinity= | den Prozess auf einen oder mehrere CPU-Kerne beschränken |
4.10.3 Control-Group Informationen anzeigen
- Control-Group Parameter der Systemd-Prozesse anzeigen
# systemd-cgls # systemd-cgtop
4.11 systemd-run
- mit
systemd-runkönnen Prozesse Ad-Hoc unter Kontrolle von Systemd gestartet werden, ohne vorher erst eine Unit-Datei schreiben zu müssen- dabei können (fast) alle Parameter aus den Unit-Dateien auf der Kommandozeile angegeben werden
- Beispiel: ein kleines CPU-Stress Programm
/usr/local/bin/my-stress
#!/bin/sh while true; do x=$((123456789/65234)) done
- Stress-Programm ohne Resource-Control starten
chmod +x /usr/local/bin/my-stress my-stress & my-stress & my-stress & my-stress &
- Stress-Programm mit
systemd-runstarten
# systemd-run -p CPUQuota=10% -p CPUAccounting=true /usr/local/bin/my-stress
Running as unit run-3104.service.
# systemctl status run-3104
-> run-3104.service - /root/./stress.sh
Loaded: loaded (/run/systemd/system/run-3104.service; static; vendor preset: disabled)
Drop-In: /run/systemd/system/run-3104.service.d
* 50-CPUAccounting.conf, 50-CPUQuota.conf, 50-Description.conf, 50-ExecStart.conf
Active: active (running) since Mon 2017-01-23 10:25:17 CET; 1min 21s ago
Main PID: 3105 (stress.sh)
CGroup: /system.slice/run-3104.service
* 3105 /bin/sh /usr/local/bin/stress
Jan 23 10:25:17 centos7.home.strotmann.de systemd[1]: Started /root/./stress.sh.
Jan 23 10:25:17 centos7.home.strotmann.de systemd[1]: Starting /root/./stress.sh...
- Systemd-run als Ersatz für
at. Sieheman systemd.timefür die Zeit-Formate
# systemd-run --on-calendar 10:31 /usr/local/bin/my-stress Running timer as unit run-3281.timer. Will run service as unit run-3281.service.
4.12 Dokumentation zu Systemd
- Blog-Serie von Lennard Pöttering: Systemd für Administratoren http://0pointer.de/blog/projects/systemd-for-admins-1.html
4.13 Systemd-Service-Unit erstellen
- Wir erstellen eine SystemD Service-Unit für den Server Dienst
$EDITOR /etc/systemd/system/simple-server.service
- Die Unit-Datei
[Unit] Description=a simple http server After=syslog.target network.target [Service] ExecStart=/usr/local/bin/simple-server [Install] WantedBy=multi-user.target
- Die neue Systemd-Service-Datei muss mit dem richtigen SELinux Label versehen werden
restorecon -R -v /etc/systemd/system/simple-server.service
- Systemd Service-Units neu laden und den Simple-Server starten
systemctl daemon-reload systemctl start simple-server systemctl enable simple-server systemctl status simple-server
4.14 systemd Sicherheit
4.14.1 Einfache Direktiven
- Units unter anderer uid/gid laufen lassen
- Zugriff auf Verzeichnisse beschränken
- Prozesslimits setzen
$EDITOR /etc/systemd/system/simplehttp.service [Unit] Description=HTTP Server [Service] Type=simple Restart=on-failure #User=karl #Group=users #WorkingDirectory=/usr/share/doc #PrivateTmp=yes #ReadOnlyDirectories=/var #InaccessibleDirectories=/home /usr/share/doc #LimitNPROC=1 #darf nicht forken #LimitFSIZE=0 #darf keine Files schreiben ExecStart=/bin/python3 -m http.server 8000
4.14.2 Weitere Directiven und Isolationstechniken
- PrivateNetwork=yes
- CapabilityBoundingSet=CAP_CHOWN CAP_KILL
- CapabilityBoundingSet=~CAP_SYS_PTRACE
- AmbientCapabilities=CAP_NET_BIND_SERVICE
- DeviceAllow=/dev/null rw
- ProtectSystem={ full | strict }
- ProtectHome=
4.14.3 Selbstanalyse
systemd-analyze securitysystemd-analyze security <unit.service>
4.14.4 Übung:
- Teste den Dienst
simple-servermit systemd-analyze. Erhöhe die Sicherheit des Dienstes mit den angegebenen Empfehlungen. Versuche einen Score von unter 5 zu bekommen. Stelle sicher das der Dienst immer noch funktioniert und die Webseite ausliefert.
4.15 Systemd-Journal
4.15.1 Systemd-Journal Auffrischung
- Die "Logdateien" im systemd, aka das Journal, ist eine binäre Datenbank mit umfassenden Suchwerkzeugen
- contra
- kein KISS Design
- schlechte post-mortem Analyse
- nicht mehr kompatibel zu alten Logauswertungen (z.B. logwatch)
- pro
- Metainfos nicht mehr fälschbar (weil vom Daemon)
- Außerhalb des laufenden
systemd-journaldnicht mehr fälschbar (Verkettung der Log-Einträge per kryptografischen Hashes) - wartungsfrei (kein logrotate)
- kann applikationsspezifische Werte aufnehmen
- umfangreiche Abfragemöglichkeiten
- Journal-Dateien
/var/log/journal/<machine-id>← persistent/run/log/journal/<machine-id>← dynamisch
Die machine-id steht in
/etc/machine-idund wird automatisch generiert oder mitsystemd-machine-id-setuperzeugt. Das Verzeichnis/var/log/journalmuss vorhanden sein; systemd-journald loggt andernfalls nur temporär. - Journal abfragen mit journalctl
- Alle Journalmeldungen anzeigen
journalclt
- gleich ans Ende springen
journalctl -e
- Datei verfolgen mit allen Metadaten und Catalog-Meldungen
journalctl -f -a -x
- Meldungen eines bestimmten Dienstes anzeigen
journalctl _SYSTEMD_UNIT=ssh.service journalctl -u ssh.service journalctl /usr/sbin/sshd
- Kernel Meldungen (dmesg)
journalctl -k
- alle Felder aufschlüsseln
journalctl -o verbose journalctl -o json-pretty
(alle Felder, die mit '_' beginnen, sind interne Felder und werden intern vom journald gesetzt und nicht vom Client. Somit sind sie nicht leicht manipulierbar.)
- Meldungen seit dem letztem Boot
journalctl -b
- in einem bestimmten Zeitraum
journalctl --since "2026-01-10" --until "2026-01-24 12:00"
- ab einem bestimmten Level
journalctl -p 4 journalctl -p warning
- Ins Journal schreiben
ls | systemd-cat
- Größe der Journal-Datenbank beschränken: in der Datei
/etc/systemd/journald.conf:
SystemMaxUse=100M SystemKeepFree=1G
4.15.2 Journal-Plattenverbrauch
- Dateisystemverbrauch des Systemd-Journals abfragen
# journalctl --disk-usage Archived and active journals take up 4.0G in the file system.
- Journal-Datenbank verkleinern
# journalctl --vacuum-size=500M # journalctl --disk-usage Archived and active journals take up 488.1M in the file system.
5 Namespaces mit systemd-nspawn Refresh
5.1 Namespaces
- Dieses Kapitel zeigt Namespaces, eine Standard-Technologie des Linux-Kernel
- Namepspaces 'virtualisieren' die Sicht auf Ressourcen des Linux-Kernels
- Programme wie Docker, Podman, Chrome, systemd-nspawn, LXC/LXD, Firejail etc. benutzen die Namespaces im Linux-Kernel
- Verfügbare Namespaces in Linux
| Namespace | Konstante | Isolation |
|---|---|---|
| Cgroup | CLONE_NEWCGROUP | Cgroup root Verzeichnis (Ressourcen wie CPU/RAM) |
| IPC | CLONE_NEWIPC | System V IPC, POSIX message queues |
| Network | CLONE_NEWNET | Network devices, stacks, ports, Firewall etc. |
| Mount | CLONE_NEWNS | Mount points (Dateisysteme) |
| PID | CLONE_NEWPID | Process IDs |
| User | CLONE_NEWUSER | Benutzer und Gruppen IDs |
| UTS | CLONE_NEWUTS | Hostname und NIS Domain Name |
5.2 Container/Namespace mit Systemd
- Jedes Linux mit Systemd bringt mächtige Container-Verwaltungs-Werkzeuge mit
systemd-nspawnarbeitet neben Image-Dateien für Container auch mit installieren Linux-Root-Dateien in einem beliebigen Verzeichnis auf dem Container-Host-System- Damit ist es sehr einfach, ein Container-System aufzusetzen und Dateien zwischen dem Container-Host und dem Linux im Container auszutauschen
5.2.1 Container Linux manuell installieren
- In diesem Kapitel werden wir das bestehende Rocky-Linux des
Host-Systems der virtuellen Maschine in ein Verzeichnis kopieren
und dort innerhalb eines Namespaces mittels
systemd-nspawnstarten - Die Systemd-Container Befehle installieren
# dnf install systemd-container
- Anlegen des Verzeichnis
# mkdir -p /srv/container/namespace1
- Root-Dateisystem des Host-Linux anschauen
# ls -l /
- Kopieren aller Daten aus dem Host-Dateisystem in das neue
Verzeichnis. Die Pseudo-Dateisysteme
/dev,/proc,/tmpund/runlassen wir aus, diese werden vonsystemd-nspawnspäter automatisch mit den korrekten Daten gefüllt. Einige Verzeichnisse wie/afsoder/bootwerden im Namespace nicht benötigt.
# cp --reflink -a /bin /etc /home /lib /lib64 /root /sbin /usr /var /srv/container/namespace1/
- Frage: was machen die Parameter
-aund--reflink? - Die leeren Verzeichnisse für die Mounts der Pseudo-Dateisysteme
erstellen
# cd /srv/container/namespace1 # mkdir dev proc run tmp # cd /root
- Die Machine-ID Datei im Namespace löschen, damit nicht beide
Systeme (Host und Namespace) die gleiche Machine-ID besitzen. Beim
Starten des Namespace wird diese Datei neu erstellt
# rm /srv/container/namespace1/etc/machine-id
- In den Namespace wechseln, um dort änderungen druchzuführen ohne
das System im Namespace zu starten. Es wird eine Shell gestartet.
# systemd-nspawn -D /srv/container/namespace1
- Zeige die laufenden Prozesse im Namespace mittels
psundtopan - Namespace verlassen durch beenden der Shell
# exit
- Das Linux im Namespace starten (booten)
# systemd-nspawn -bD /srv/container/namespace1
- Übung
- Starte das Linux-System im Namespace
- Melde Dich am System an (warum funktionieren Benutzername und Passwort?)
- Vergleiche den Inhalte vom
/etc/machine-idauf dem Host und im Namespace - Vergleiche den Netzwerkstatus innerhalb des Namespace mit dem Host
- Zeige die Prozesse im Namespace an
- Installiere den NGINX-Webserver im Namespace mit
dnf install nginx - Benutze
systemctlum den NGINX Webserver anzuschalten und zu starten - Konfiguriere den Webserver so um, dieser auf den Port 8080 horcht
(Datei
/etc/nginx/nginx.conf) - Restarte den NGINX-Webserver, so das dieser die neue Konfiguration übernimmt
- Installiere das Programm
lsof(List open files)dnf install lsof - Teste mit
lsof -idas der NGINX nun auf Port 8080 horcht - Versuche mit einem Web-Browser den Web-Server im Namespace zu erreichen: http://selinuxNNN.linux-sicherheit.org:8080
- Gibt es Probleme? Woran können diese liegen? SELinux? Firewall? Namespace-Netzwerk?
5.2.2 Übungen:
- Während der Namespace gestartet ist
- Eine weitere Root-Shell auf der virtuelle Maschine öffnen und von
dort die Prozesse auf dem Host anschauen: ist der
nginxProzess im Namespace sichtbar? - Im Namespace das Programm
stress-nginstallieren und mit einem CPU-Worker starten:stress-ng -C 1 - Vom Host aus die Auslastung beobachten mit
systemd-cgtop - Vom Host aus die Controll-Group Strukturen mit
systemd-cglsanschauen - Überwache die Systemauslastung auf dem Host mit
top. Der Prozessstress-ngsollte knapp 100% der CPU benutzen - Finde den Namen des
scopedes gestarteten Namespaces mitsystemd-cgls - Beschränke die CPUQuota des Namespace-Scope auf dem Host mit dem
Befehl
systemctl set-property ...und der EinstellungCPUQuota=20% - Der Prozess
stress-ngsollten dann nur noch 20% der CPU verbrauchen
- Eine weitere Root-Shell auf der virtuelle Maschine öffnen und von
dort die Prozesse auf dem Host anschauen: ist der
5.2.3 Namespace stoppen
- Ein in einem Namespace gestartetes Linux-System kann mit dem Befehl
poweroffgestoppt, und mit dem Befehlrebootneu gestartet werden- Vor der Eingabe dieser Befehle sollte geprüft werden, das diese im Namespace und nicht auf dem Host eingegeben werden
5.2.4 Netzwerkanpassungen eines Namespace
- Container mit privatem Netzwerk-Namespace starten (keine Verbindung zum Host-Netzwerk):
systemd-nspawn -bD /srv/container/namepspace1 --private-network
- Container mit privatem Netzwerk-Namespace starten und eine virtuelle Netzwerkverbindung (veth) zwischen dem Host und dem Namespace herstellen
systemd-nspawn -bD /srv/container/namepspace1 --network-veth
- Übung
- starte den Namespace mit
--network-veth - finde die virtuellen Netzwerkschnittstellen in Namespace und auf dem Host
- Konfiguriere beide Netzwerkschnittstellen mit je einer IP-Adresse
aus dem gleichen (privatem) IP-Adress-Subnetz. Benutze das
ipKommando. - Teste die Netzwerkverbindung zwischen Host und Namespace
- starte den Namespace mit
5.3 Machinectl
- Systemd-Befehle um einen Container vom Host aus zu kontrollieren
machinectl list machinectl status namepspace1 machinectl poweroff namespace1 machinectl terminate namespace1 machinectl kill namespace1
- Eine Shell vom Host innerhalb eines gestarteten Namespace erstellen
# machinectl shell namespace1
5.4 nsenter
- Per
nsenterkönnen wir uns mit jedem Linux-Namespace verbinden. Dabei kann mit Parametern detailiert bestimmt werden, welche Namespaces für den gestarteten Prozess (hier eine Shell) aktiv werden sollen- So kann man z.B.
- Per nsenter mit dem Container verbinden (es wird eine Prozess-ID eines Container-Prozesses benötigt!)
nsenter -m -u -i -n -p -t <pid-im-container> /bin/bash
- Der Befehl
machinectl status namespace1zeigt die Prozesshierarchie innerhalb des Namespaces
6 SELinux
6.1 SELinux Dokumentation
- SELinux-Module werden mit (automatisch generierten)
man-Pages ausgeliefert - Diese Manpages sind auf einem Red Hat/CentOS-System nicht standardmäßig installiert
- Sie können aus den SELinux-Richtlinienquellen hinzugefügt werden
# dnf install -y selinux-policy-devel # sepolicy manpage -a -p /usr/share/man/man8
- Während das SELinux-Modul
bindgenannt wird, heißt die Manpagenamed_selinux.- Diese Manpage dokumentiert die
named process types, die neben BIND 9 auch für den Unbound-Resolver verwendet werden:# man named_selinux
- Diese Manpage dokumentiert die
6.2 Audit Subsystem
6.2.1 Beispiele für Audit-Abfragen
- Alle Audit-Einträge zum Thema "sudo" zeigen
ausearch -i -x sudo
- Report über fehlgeschlagende Anmeldeversuche
ausearch -m USER_AUTH,USER_ACCT --success no
- Alle Audit-Meldungen für Benutzer UID 1000
ausearch -ua 1000 -i
- Fehlgeschlagende Syscalls seit gestern
ausearch --start yesterday --end now -m SYSCALL -sv no -i
6.3 SELinux erkunden
- SELinux Hilfspakete installieren
dnf install policycoreutils setools libselinux-utils selinux-policy-doc setools-console dnf install policycoreutils-python3 selinux-policy-devel policycoreutils-newrole
6.3.1 SELinux Label auf Dateien
- SELinux Label (Context) auf Dateien anzeigen
ls -lZ <pfad>
- Welche Dateien/Verzeichnisse unter
/etcsind vom SELinux Typsystem_conf_t? - Welchen SELinux Type haben neue Dateien im Heimverzeichnis des
Benutzers
user(ggf. eine Datei neu anlegen)? - Erstelle eine sortierte Liste der SELinux Datei-Typen (3tes Feld
im SELinux Label user:role:type) im Verzeichnis
/usr/sbin.
6.3.2 SELinux Label auf Prozessen
- SELinux Label auf Prozessen anzeigen
ps -auxZ
6.3.3 SELinux Label auf dem aktuellen Benutzer anzeigen
# id -Z
6.3.4 SELinux Status abfragen
- Allgemeinen SELinux Status abfragen
sestatus
- Detaillierten SELinux Status abfragen
sestatus -v
- SELinux "enforcement" Status anzeigen
getenforce
- Verfügbare SELinux Module auflisten
semodule -l | less
- Die kompilierte (binäre) Richtlinien (Policy) Datei
ls -lh /etc/selinux/targeted/policy/
- Statistiken über den Access-Vector-Cache (AVC)
# avcstat lookups hits misses allocs reclaims frees 797921406 797847473 73933 73933 71040 73429
6.4 SELinux Funktions-Beispiel
- SELinux in den enforcing Modus schalten
setenforce 1
- Apache Webserver installieren und starten
dnf install httpd systemctl enable --now httpd
- Kleine Webseite mit einem Editor anlegen ($EDITOR durch
vi,vim,nano,emacsetc ersetzen)
$EDITOR /var/www/html/index.html
- Inhalt der HTML-Datei
/var/www/html/index.html(Vorschlag)
<html> <body> <h1>Apache Webserver</h1> </body> </html>
- SELinux Security Context auf der Datei anzeigen
ls -lZ /var/www/html/index.html
- Port 80 in der Firewall erlauben
# firewall-cmd --zone=public --add-service=http --permanent # firewall-cmd --reload
- Die Webseite sollte nun unter Port 80 (http, nicht https) mittels eines Webbrowsers abrufbar sein
6.4.1 Ein SELinux-Problem für den Apache Webserver erzeugen
- Eine Datei
index.htmlDatei im Heim-Verzeichnis des Benutzersrooterstellen und in das Apache-WWW-Verzeichnis verschieben (nicht kopieren):rm /var/www/html/index.html $EDITOR /root/index.html mv /root/index.html /var/www/html/index.html ls -lZ /var/www/html/index.html
- Apache sollte nun nicht mehr in der Lage sein, die HTML-Datei auszuliefern (Default-Apache 2 Webseite erscheint)
- SELinux LSM-Meldungen im Audit-Log zum Prozess
httpdanzeigen (Modulavc= Access Vector Cache)ausearch -m avc -ts recent -c httpd -i
- SELinux Sicherheits-Kontext der Datei prüfen
matchpathcon -V /var/www/html/index.html
- Es wird angezeigt das der SELinux Sicherheits-Kontext der Datei nicht korrekt ist. SELinux blockiert daher die Zugriffe vom Apache Webserver auf diese Datei
6.4.2 Das SELinux Problem mit dem Apache Webserver lösen
- SELinux Security Context für Apache-Dateien anzeigen
sesearch --allow --source httpd_t --target httpd_sys_content_t --class file
- SELinux Sicherheits-Kontext anpassen (manuell mit dem Befehl
chcon(Change Context)chcon --type httpd_sys_content_t /var/www/html/index.html
- (Alternativ) SELinux Sicherheits-Kontext aus der SELinux Policy
angleichen
restorecon -v /var/www/html/index.html
6.5 SELinux - Policy Development
- Für dieses Kapitel arbeiten wir auf dem VM Maschinen
- Andere Web-Server (Apache/NGINX etc) auf der VM stoppen
- Für die Dauer dieser Übung die Firewall auf der VM deaktivieren
systemctl stop firewalld systemctl stop httpd
6.5.1 SELinux Policy erstellen
- In diesem Kapitel werden wir eine SELinux Richtlinie (Policy) für
einen Dienst entwickeln, welcher bisher noch nicht durch SELinux
geschützt ist
- Dies kann in der Praxis für Software notwendig werden, welche von externen Entwicklern geliefert wurde oder im eigenen Hause entwickelt wird
- Unsere Beispiel-Anwendung ist ein sehr einfacher Webserver
- Für die Entwicklung neuer SELinux Richtlinien benötigen wir die Pakete für die SELinux Policy-Entwicklung (diese sind im Kurs ggf. schon installiert)
dnf install policycoreutils-python3 selinux-policy-devel
- Nach der Installation dieser Pakete befinden sie die SELinux Policy
Quelldateien (der von Red Hat und der Community erstellen
Richtlinien) im Verzeichnis
/usr/share/selinux/devel/ls -l /usr/share/selinux/devel/ ls -l /usr/share/selinux/devel/include/contrib/
6.5.2 Ein einfacher Web-Server
- Im Kapitel "Vorbereitung der Lab-Umgebung" haben wir den Dienst
simple-servererstellt. - Wir starten den Dienst
simple-serverauf dem Host - Wenn wir uns die SELinux Label des Dienstes anzeigen lassen sehen
wir das dieses Dienst
unconfinedist, also nicht durch SELinux abgesichert
ps -eZ | grep simple ls -lZ /usr/local/bin/simple-server
6.5.3 Initiales SELinux Policy Modul
- Wir erstellen ein neues Verzeichnis fuer das neue SELinux Policy Modul
mkdir ~/selinux-src cd ~/selinux-src
- Der Befehl
sepolicy generateerzeugt eine Vorlage für ein SELinux Policy Modul
sepolicy generate -n simple-server --init /usr/local/bin/simple-server
- Es werden drei SELinux Policy Quelldateien erstell
simple-server.te- Type Enforcement Quellcode - auf welche Datei-Typen darf der Prozess zugreifensimple-server.fc- File Context Quellcode - welche Datei-Typen werden benutzt (und in welchen Pfaden liegen diese)simple-server.if- Interface Quellcode - Definiert die Übergänge zwischen den Dateisystem und Prozess Typen, und definiert die Regeln für die Richtliniensimple-server_selinux.spec- Quelldatei für ein RPM Paketsimple-server.sh- Shell Skript zum bauen des RPM Pakets des SELinux Policy Moduls
- Diese Dateien können wir uns anschauen
- Die Policy ist im
permissiveModus!
less simple-server.te less simple-server.fc less simple-server.if
- Wir testen diese SELinux Policy indem wir diese übersetzen und ein
RPM-Paket erstellen. Das Paket
rpm-buildwird benötigt um ein RPM-Paket zu bauen
dnf -y install rpm-build sh simple-server.sh ls -l
- Die neue SELinux Policy befindet sich in der Datei
simple-server.pp. Dieses neue SELinux Policy-Modul kann nun geladen und aktiviert werden
semodule -i simple-server.pp
- Die neue Policy wirkt sich nicht auf schon gestartete Prozesse
aus. Daher stoppen wir den vorher gestarteten
simple-serverProzess
systemctl stop simple-server
- Den Simple-Server starten
systemctl start simple-server
- Nun den Dienst benutzen (Mit dem Web-Browser auf Port 8080 zugreifen). Das SELinux Modul ist noch im Permissive Mode, Verstösse gegen die Policy werden im Audit-Log protokolliert
ausearch -m avc -ts recent -c simple-server
- Auch das Systemd-Journal liefert Fehlermeldungen über
SELinux-Troubleshoot Modul
setroubleshoot
journalctl | grep setroubleshoot
- Erklärungen zu den Policy-Fehlermeldungen ausgeben
ausearch -m avc -ts today -c simple-server | audit2why | less
- Mittels des Programms
audit2allowlassen sich Policy-Regeln aus den Audit-Meldungen erstellen. Diese Regeln sind selten 100% korrekt und müssen oft nachbearbeitet werden, helfen aber enorm bei der Erstellung eines Regelwerkes- Der Befehl
sepolgen-ifgenerzeugt aus den SLinux Interface-Dateien des Systems Hilfdateien für die Erstellung der Policy-Dateien - Der Befehl
audit2allow -Rgibt die SELinux Policy-Regeln auf dem Terminal aus. Diese bauen wir per copy-n-paste in die Type-Enforcement-Quelldateisimple-server.teein. Dabei muss auf die korrekte Reihenfolge der Abschnitte geachtet werden (requireBlock unter Deklarationen,allowAusdrücke darunter):
- Der Befehl
sepolgen-ifgen -v
ausearch -m avc -ts today -c simple-server | audit2allow -R
require {
type simple-server_t;
class tcp_socket { bind create setopt accept listen };
}
#============= simple-server_t ==============
allow simple-server_t self:tcp_socket { bind create setopt accept listen };
corenet_tcp_bind_generic_node(simple-server_t)
corenet_tcp_bind_http_cache_port(simple-server_t)
- Neue Policy-Regeln in die Policy einfügen, Modul entfernen, neu kompilieren und dann neu laden
semodule -r simple-server sh ./simple-server.sh semodule -i simple-server.pp systemctl restart simple-server
- Die Anwendung benutzen und testen, danach wieder das Audit-Log auf
SELinux Fehler des
simple-serverProzesses prüfen. GGf. neue Regeln erstellen und Modul und Programm neu laden - Diese Schritte wiederholen bis keine SELinux Meldungen mehr im
Audit-Log auftauchen
ausearch -m avc -ts recent -c httpd -i <no matches>
- Die Anwendung ggf. für eine gewisse Zeit in Produktion im permissive Modus betreiben und auf SELinux Fehler prüfen
- Treten keine Fehler mehr auf, dann die Zeile
permissive simple-server_t;in der Type-Enforcement Datei auskommentieren und das Modul im enforcing Modus betreiben - Schalten wir nun das
simple-serverModul in den enforcing Modus, werden wir feststellen das das Programm doch nicht wie gewünscht funktioniert - Ein Trace des laufenden Programms mittels
straceoder eBPF oder bpftrace zeigt das die Syscallsshutdownundwritefehlschlagen. Diese werden von SELinux unterbunden, aber nicht an das Audit-Subsystem gemeldet. - Aufgabe: Trage die Syscalls
shutdownundwritein die Policy ein, übersetze die Policy und teste erneut
6.5.4 Die "DoNotAudit" Regeln ausschalten
- Entwickler von SELinux-Policies können bestimmte Regeln vom
Auditing ausschliessen
- Um übermässiges Logging im Audit zu vermeiden
- Verstösse gegen SELinux-Regeln, welche mit
donotauditmarkiert sind, werden nicht im Audit-Log vermerkt - Bei der Entwicklung von neuen SELinux Policies kann dies stören, denn hier möchte man im Audit-Log ein möglichst vollständiges Bild aller Verstösse bekommen
- Die
donotauditRegeln in der SELinux-Richtline ausschalten# semodule -DB
- Um die
donotauditRegel wieder zu aktivieren# semodule -B
6.5.5 Eine Änderung an einer SELinux Policy
- Unser "Simple-Server" lernt das Logging in eine Datei. In der
Quelldatei-Box sehen wir die Änderungen an dem Quellcode des
simple-server.cProgramms:
--- simple-server1.c 2022-10-25 09:22:06.684216579 +0000
+++ simple-server2.c 2022-10-26 08:53:33.319698944 +0000
@@ -19,6 +19,13 @@
int main()
{
int one = 1, client_fd;
+ FILE *f = fopen("/var/log/simple-server.log", "a");
+ if (f == NULL)
+ {
+ printf("Error opening file!\n");
+ exit(1);
+ }
+
struct sockaddr_in svr_addr, cli_addr;
socklen_t sin_len = sizeof(cli_addr);
@@ -40,7 +47,8 @@
listen(sock, 5);
while (1) {
client_fd = accept(sock, (struct sockaddr *) &cli_addr, &sin_len);
- printf("got connection\n");
+ fputs("got connection\n",f);
+ fflush(f);
if (client_fd == -1) {
perror("Can't accept");
- Das gepatchte Programm. Dieses Programm schreibt nun ein einfaches
Log in die Datei
/var/log/simple-server.log. Den Nachfolgenden Quellcode in die Dateisimple-server2.cspeichern
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <err.h>
char response[] = "HTTP/1.1 200 OK\r\n"
"Content-Type: text/html; charset=UTF-8\r\n\r\n"
"<!DOCTYPE html><html><head><title>Bye-bye baby bye-bye</title>"
"<style>body { background-color: #111 }"
"h1 { font-size:4cm; text-align: center; color: black;"
" text-shadow: 0 0 2mm red}</style></head>"
"<body><h1>Goodbye, world!</h1></body></html>\r\n";
int main()
{
int one = 1, client_fd;
FILE *f = fopen("/var/log/simple-server.log", "a");
if (f == NULL)
{
printf("Error opening file!\n");
exit(1);
}
struct sockaddr_in svr_addr, cli_addr;
socklen_t sin_len = sizeof(cli_addr);
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0)
err(1, "can't open socket");
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(int));
int port = 8080;
svr_addr.sin_family = AF_INET;
svr_addr.sin_addr.s_addr = INADDR_ANY;
svr_addr.sin_port = htons(port);
if (bind(sock, (struct sockaddr *) &svr_addr, sizeof(svr_addr)) == -1) {
close(sock);
err(1, "Can't bind");
}
listen(sock, 5);
while (1) {
client_fd = accept(sock, (struct sockaddr *) &cli_addr, &sin_len);
fprintf(f,"got connection\n");
fflush(f);
if (client_fd == -1) {
perror("Can't accept");
continue;
}
write(client_fd, response, sizeof(response) - 1); /*-1:'\0'*/
close(client_fd);
}
}
- In der SELinux-Policy-Quelldatei
simple-server.fcdefinieren wir den neuen Datei-Kontextvar_log_tfür die Log-Datei
/var/log/simple-server.log -- gen_context(system_u:object_r:var_log_t,s0)
- Die SELinux Type-Enforcment Datei für
simple-serverauf Permissive stellen und das SELinux-Modul neu übersetzen und laden - Den neuen Server-Dienst übersetzen, den alten
simple-serverProzess stoppen, die neue Programm-Datei nach/usr/local/binkopieren, das SELinux Label anpassen und den Dienst neu starten
gcc -o simple-server simple-server2.c systemctl stop simple-server cp simple-server /usr/local/bin restorecon -R -v /usr/local/bin/simple-server systemctl start simple-server
- Per Web-Browser die Webseite auf
http://selinuxNNN.linux-sicherheit.org:8080/aufrufen. - Neue SELinux Audit-Meldungen tauchen auf
# ausearch -m avc -ts recent -c simple-server
----
time->Wed Aug 24 21:17:34 2016
type=SYSCALL msg=audit(1472073454.717:1390): arch=c000003e syscall=2 success=yes exit=3 a0=400ae2 a1=441 a2=1b6 a3=21000 items=0 ppid=1 pid=7869 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=4294967295 comm="simple-server" exe="/usr/local/bin/simple-server" subj=system_u:system_r:simple-server_t:s0 key=(null)
type=AVC msg=audit(1472073454.717:1390): avc: denied { open } for pid=7869 comm="simple-server" path="/var/log/simple-server.log" dev="vda1" ino=268256 scontext=system_u:system_r:simple-server_t:s0 tcontext=system_u:object_r:var_log_t:s0 tclass=file
type=AVC msg=audit(1472073454.717:1390): avc: denied { create } for pid=7869 comm="simple-server" name="simple-server.log" scontext=system_u:system_r:simple-server_t:s0 tcontext=system_u:object_r:var_log_t:s0 tclass=file
type=AVC msg=audit(1472073454.717:1390): avc: denied { add_name } for pid=7869 comm="simple-server" name="simple-server.log" scontext=system_u:system_r:simple-server_t:s0 tcontext=system_u:object_r:var_log_t:s0 tclass=dir
type=AVC msg=audit(1472073454.717:1390): avc: denied { write } for pid=7869 comm="simple-server" name="log" dev="vda1" ino=258603 scontext=system_u:system_r:simple-server_t:s0 tcontext=system_u:object_r:var_log_t:s0 tclass=dir
- Die Erweiterungen zur SELinux Policy ausgeben, prüfen und in die
Type-Enforcement-Datei
simple-server.teeinfügen:
# ausearch -m avc -ts recent -c simple-server | audit2allow -R
require {
type simple-server_t;
}
#============= simple-server_t ==============
auth_log_filetrans_login_records(simple-server_t)
logging_manage_generic_logs(simple-server_t)
simple-serverSELinux Modul entfernen, Policy neu übersetzen, Modul neu laden, testen- Ggf. fehlen die Regeln um Log-Dateien anlegen und schreiben zu
dürfen. Wenn dies der Fall ist, die
donotauditFunktion in der SELinux-Policy deaktivieren- Ein Blick in die bestehenden SELinux Policy Quelldateien von ähnlichen Programmen kann (auch) helfen
- Wir fügen der Type-Enforcement-Quelldatei den Typ
var_log_tund die Klassenfile(Syscallscreate,openundwrite) unddir(Verzeichnis mit den Syscallswriteundadd_name) hinzu
require {
type simple-server_t;
type var_log_t;
class tcp_socket { bind create setopt accept listen shutdown write };
class file { create open write };
class dir { write add_name };
}
- Wir fügen der Type-Enforcement-Quelldatei die Regeln für den
Zugriff auf Dateien und Verzeichnisse im
/var/logVerzeichnisbaum hinzu:
allow simple-server_t var_log_t:file { create open write };
allow simple-server_t var_log_t:dir { write add_name };
- Das Makro
logging_rw_generic_log_dirserlaubt das Schreiben von Log-Dateienlogging_rw_generic_log_dirs(simple-server_t)
- Solange die Policy anpassen, bis keine Permission-Meldungen im Audit-Log erscheinen
- Prüfen, das die Log-Datei korrekt erstellt wird
6.6 Hilfsmittel zur Erstellung von SELinux-Policy Regelwerken
strace- Kann die benutzten Systemcalls eines laufenden Prozesses ausgebenautrace- Kann die benutzten Systemcalls eines Prozessaufrufs ausgebennm- kann die Aufrufe in die C-Bibliothek (GLIBC) ausgeben:
# nm /usr/local/bin/simple-server | grep @GLIBC
U accept@GLIBC_2.2.5
U bind@GLIBC_2.2.5
U close@GLIBC_2.2.5
U err@GLIBC_2.2.5
U htons@GLIBC_2.2.5
U __libc_start_main@GLIBC_2.34
U listen@GLIBC_2.2.5
U perror@GLIBC_2.2.5
U puts@GLIBC_2.2.5
U setsockopt@GLIBC_2.2.5
U socket@GLIBC_2.2.5
U write@GLIBC_2.2.5
- eBPF und
bpftracesind sehr gute Hilfsmittel, um Prozesse und auch das Verhalten von Prozessen unter SELinux zu analysieren
6.6.1 SELinux Module ausschalten
- SELinux Module können selektiv deaktiviert/aktiviert werden
- Um nur das BIND 9 SELinux-Modul zu deaktivieren
# semodule -d bind
6.6.2 SEModule anschalten
- Um das BIND 9 SELinux-Modul zu aktivieren
# semodule -ve bind Attempting to enable module 'bind': Ok: return value of 0. Committing changes: Ok: transaction number 6.
6.7 SELinux Fehlkonfigurationen finden
6.7.1 Reports des Linux Audit Subsystem
- Verstöße gegen SELinux-Richtlinien werden mit dem Linux Audit Subsystem protokolliert
- Mit dem Kommando
ausearchkönnen Sie die Richtlinienverletzungen eines bestimmten Prozesses auflisten-m avclistet LSM-Richtlinienverstöße auf-x /usr/sbin/namedfiltert nach Verstößen dieses Prozesses-i(interpretieren) gibt die Daten in lesbarer Form aus
6.7.2 Nicht übereinstimmende Dateitypkennzeichnung
- Das SELinux-System verweigert Prozessen den Zugriff auf Zonen- oder Konfigurationsdateien, wenn die Dateilabel nicht korrekt sind
- Gründe für falsche oder fehlende Dateilabel
- Das Linux-System wurde mit deaktiviertem SELinux betrieben
- Die Dateien befinden sich in einem nicht standardmäßigen
Verzeichnis (z.B. nicht in
/etcoder/var/named) - Die Dateien wurden in einem nicht standardmäßigen Verzeichnis erstellt und dann in das richtige Verzeichnis verschoben. Die Datei-Bezeichnungen werden bei der Erstellung einer Datei zugewiesen und ändern sich nicht, wenn sie innerhalb des gleichen Dateisystem verschoben werden.
6.7.3 SELinux Label anzeigen (1/2)
- SELinux Sicherheits-Kontext (Label) auf einer Datei anzeigen
# secon --file /etc/shadow user: system_u role: object_r type: shadow_t sensitivity: s0 clearance: s0 mls-range: s0
6.7.4 SELinux Label anzeigen (2/2)
- Sicherheitskontext auf einem Prozess anzeigen
# secon --pid $(pgrep dbus) user: system_u role: system_r type: system_dbusd_t sensitivity: s0 clearance: s0:c0.c1023 mls-range: s0-s0:c0.c1023
6.7.5 Das richtige SELinux Label finden
- Der Befehl
matchpathcon(Match Path Context) meldet Dateien, bei denen das Dateilabel nicht mit der SELinux-Richtlinie übereinstimmen- Der Befehl meldet auch die erwarteten Dateilabel-Typen
# matchpathcon -V /var/named/named.localhost /var/named/named.localhost has context system_u:object_r:etc_t:s0, should be system_u:object_r:named_zonefile
6.7.6 Ändern des Dateilabels
- Der Befehl
chcon(change SELinux context) kann verwendet werden, um den Typ des Dateilabel zu ändern:# chcon --type named_cache_t /var/named/zonefile.db
6.7.7 Anwenden des korrekten Label aus der Richtlinie
- Der Befehl
restoreconpasst das Label einer Datei so an, dass es mit dem von der SELinux-Richtlinie erwarteten Label übereinstimmt# restorecon -v /var/named/named.localhost Relabeled /var/named/named.localhost ... from system_u:object_r:etc_t:s0 ... to system_u:object_r:named_zone_t:s0
6.7.8 Anpassen des erwarteten Dateikontextes für eine einzelne Datei
- Wenn Konfigurations- oder Datendateien an einem nicht standardmäßigen Speicherort gespeichert sind, sollte die SELinux-Richtlinie angepasst werden, um das richtige Kontextlabel zuzuordnen
- Der Befehl
semanage fcontext -afügt einen Dateikontext Label zur SELinux-Richtlinie hinzu.
6.7.9 Anpassen des erwarteten Dateikontextes für eine einzelne Datei
- Die Dateien werden nicht automatisch neu gekennzeichnet. Verwenden
Sie
restrorecon, um die Dateien neu zu kennzeichnen.
# semanage fcontext -a -t named_zone_t /srv/bind/zones/primary/example.com.db
# restorecon -vr /srv/bind/zones
Relabeled /srv/bind/zones/primary/example.com.db
from unconfined_u:object_r:var_t:s0
to unconfined_u:object_r:named_zone_t:s0
6.7.10 Rekursives Anpassen des Dateikontextes für alle Dateien und Verzeichnisse
- Ein neuer SELinux-Dateikontext kann rekursiv zu einem Verzeichnis
hinzugefügt werden
- Alle neuen Dateien, die in den angegebenen Verzeichnissen erstellt werden, erhalten automatisch das richtige SELinux-Dateilabel
# semanage fcontext -a -t named_zone_t --ftype f "/srv/bind/zones(/.*)?" # semanage fcontext -a -t named_zone_t --ftype d "/srv/bind/zones(/.*)?" # semanage fcontext -a -t named_cont_t --ftype f "/srv/bind/conf(/.*)?" # semanage fcontext -a -t named_conf_t --ftype d "/srv/bind/conf(/.*)?"
6.7.11 Dateikontext automatisch anpassen
- Der Hintergrundprozess
restorecondkann optional installiert und gestartet werden (Paketpolicycoreutils-restorecond), um Dateilabel von neu angelegten Dateien automatisch an die SELinux-Policy anzupassen- Je nach Einsatzbereich kann
restoreconddie Sicherheit beeinträchtigen, da SELinux-Label auf Dateien automatisch korrigiert werden - Die Datei
/etc/selinux/restorecond.conflisted die Dateien und Verzeichnisse auf, welche vonrestorecondautomatisch überwacht und berichtigt werden sollen
- Je nach Einsatzbereich kann
6.8 SELinux Richtlinien Konfigurieren
- Viele SELinux Module bieten Konfigurations-Optionen an
- Über SELinux Booleans (Schalter) können Funktionen von Richtlinien-Modulen an- bzw. ausgeschaltet werden
- Eine Liste alle SELinux Boolean-Schalter kann durch
semanage boolean -labgerufen werdenSELinux boolean State Default Description abrt_anon_write (off , off) Allow ABRT to modify public files used ... abrt_handle_event (off , off) Determine whether ABRT can run in the ... antivirus_can_scan_system (off , off) Allow antivirus programs to read non ... antivirus_use_jit (off , off) Determine whether antivirus programs ...
- Der Befehl
getseboolist eine alternative Schnittstelle zu den SELinux Schaltern
# getsebool -a abrt_anon_write --> off abrt_handle_event --> off [...] named_tcp_bind_http_port --> off named_write_master_zones --> on [...]
- Mit dem Befehl
semanage boolean -l --locallistwird eine übersicht der lokalen Schalter-Anpassungen ausgegeben# semanage boolean -l --locallist SELinux boolean State Default Description named_write_master_zones (on , on) Determine whether Bind can write [...]
- Beispiel des Ausschalten eines SELinux Schalters
# semanage boolean --modify --off named_write_master_zones
6.8.1 Alternativ: setsebool
- Als Alternative zu
semanage booleankann der Befehlsetseboolverwendet werdensetsebool named_write_master_zones off
- Um eine Änderung dauerhaft (persistent) im System zu ändern
(Reboot-Fest), muss der Schalter
-Pangegeben werdensetsebool -P named_write_master_zones off
6.8.2 SELinux Schalter
- Bei der Neu-Installation von Software auf einem SELinux System ist es sinnvoll sich mit den SELinux Schaltern für diese Software vertraut zu machen
6.9 SELinux Netzwerk-Ports
- Die SELinux Policy erlaubt Anwendungen (oder SELinux Type-Label)
die Benutzung bestimmter UDP/TCP Netzwerkports
- Versucht die Anwendung, einen anderen Port zu öffnen, so wird dies durch SELinux unterbunden
- Beispiele: Webserver, SSH-Server, DNS-Server auf Nicht-Standard-Ports
- Der Befehl
semanage port -llistet alle Port-Definitionen pro SELinux Type-Label auf- Diese Liste ist lang und umfasst alle Module, nicht nur die
aktiven SELinux Module. Benutze
grepum die Port-Konfiguration für einen SELinux-Typ zu sehen
- Diese Liste ist lang und umfasst alle Module, nicht nur die
aktiven SELinux Module. Benutze
# semanage port -l | grep ssh ssh_port_t tcp 22
- Um einen Netzwerk-Dienst auf einem nicht-standard Port unter
SELinux betreiben zu können, muss dieser Port dem SELinux-Type
hinzugefügt werden:
# semanage port -a -t ssh_port_t -p tcp 4422 # semanage port -l | grep ssh ssh_port_t tcp 22,4422
6.10 Durchsetzung der Richtlinie für Module ausschalten
- Es ist möglich einzelne SELinux Module in einen permissive Modus
zu versetzten
- In diesem Modus wird die SELinux Policy für dieses Modul nicht mehr vom Kernel durchgesetzt
- Verstösse gegen die Policy werden jedoch weiterhin im Audit-Log protokolliert
- Ein Modul (hier
httpd_tfür Apache oder NGINX Webserver) in den permissive Modus setzen
semanage permissive -a httpd_t
- Alle Module auflisten, welche im permissive Modus laufen
# semanage permissive -l
- Permissive Modus von einem Modul entfernen
semanage permissive -d httpd_t
- Permissive Modus von allen Modulen entfernen
semanage permissive -D
7 Fehlersuche
7.1 Systemd
7.1.1 Systemd-status
- Fehlerhafte Dienste auflisten
# systemctl list-units --state=failed UNIT LOAD ACTIVE SUB DESCRIPTION * gssproxy.service loaded failed failed GSSAPI Proxy Daemon Legend: LOAD > Reflects whether the unit definition was properly loaded. ACTIVE > The high-level unit activation state, i.e. generalization of SUB. SUB > The low-level unit activation state, values depend on unit type. - Details zu einem Dienst auflisten
# systemctl status gssproxy × gssproxy.service - GSSAPI Proxy Daemon Loaded: loaded (/usr/lib/systemd/system/gssproxy.service; disabled; preset: disabled) Drop-In: /usr/lib/systemd/system/service.d └─10-timeout-abort.conf Active: failed (Result: signal) since Mon 2026-03-16 07:18:48 CET; 2min 5s ago Duration: 3d 23h 14min 24.878s Invocation: ab00596fa3ac4504b1272f3a0c4fc158 Process: 1113 ExecStart=/usr/bin/gssproxy -i (code=killed, signal=KILL) Main PID: 1113 (code=killed, signal=KILL) Status: "Running, 2 service(s) configured" Mem peak: 4.1M CPU: 2.923s Mar 12 08:04:23 srv systemd[1]: Starting gssproxy.service - GSSAPI Proxy Daemon... Mar 12 08:04:23 srv systemd[1]: Started gssproxy.service - GSSAPI Proxy Daemon. Mar 16 07:18:48 srv systemd[1]: gssproxy.service: Main process exited, code=killed, status=9/KILL Mar 16 07:18:48 srv systemd[1]: gssproxy.service: Failed with result 'signal'. Mar 16 07:18:48 srv systemd[1]: gssproxy.service: Consumed 2.923s CPU time, 4.1M memory peak.
7.1.2 Journal
- Log-Meldungen zu einem Dienst anschauen
# journalctl -u gssproxy --since today Mar 16 07:18:48 srv systemd[1]: gssproxy.service: Main process exited, code=killed, status=9/KILL Mar 16 07:18:48 srv systemd[1]: gssproxy.service: Failed with result 'signal'. Mar 16 07:18:48 srv systemd[1]: gssproxy.service: Consumed 2.923s CPU time, 4.1M memory peak. Mar 16 07:23:18 srv systemd[1]: Starting gssproxy.service - GSSAPI Proxy Daemon... Mar 16 07:23:18 srv systemd[1]: Started gssproxy.service - GSSAPI Proxy Daemon.
- Logmeldungen eines Dienstes verfolgen (wie
tail -f /var/log/logdatei.log)
# journalctl -fu gssproxy
- Im Journal nach einem Wort suchen
# journalctl -u gssproxy --grep kill -- Boot c2bdc564a8dc44d4b3ddce21527094b5 -- Mar 16 07:18:48 srv systemd[1]: gssproxy.service: Main process exited, code=killed, status=9/KILL
7.2 Namespace
7.2.1 Machinectl
- Liste aller von
machinectlunterstützten virtualisierten Systeme
# machinectl
- Status eines Namespaces/Containers/virtuellen Maschine abfragen
# machinectl status namespace1
- Eine Shell in einem Namespace erstellen
# machinectl shell namespace1
- Alternativ, falls
machinectl shellfehltschlägt: Per nsenter mit dem Container verbinden (es wird eine Prozess-ID eines Container-Prozesses benötigt!)
nsenter -m -u -i -n -p -t <pid-im-container> /bin/bash
- Der Befehl
machinectl status namespace1zeigt die Prozesshierarchie innerhalb des Namespaces - Namespace herunterfahren
# machinectl poweroff namespace1
- Namespace hart beenden (kann zu Datenverlust führen!)
# machinectl terminate namespace1
- Prozesse des Namespace per
killSignal beenden# machinectl kill namespace1 # sendet "TERM" signal # machinectl --signal=kill kill namespace1 # sendet "KILL" signal
- Journal innerhalb des Namespace anschauen
# journalctl -M namespace1 ...
- Systemctl von Host innerhalb eines Namespace ausführen
# systemctl -M namespace1 ...
7.2.2 CGroups
- Hierarchie der CGroups anzeigen
# systemd-cgls
- Cgroups eines Namespace anzeigen
# systemd-cgls -M namespace1
- Auslastung der CGroups anzeigen
# systemd-cgtop
- Auslastung der CGroups nur eines Namespace anzeigen
# systemd-cgtop -M namespace1
7.2.3 ATOP
atopist ein Anzeigeprogramm für Systemressourcen.atopkann die Pressure Stall Information des Linux-Kernel anzeigen (siehe https://andrestc.com/post/pressure-stall-information/)atopzeigt Prozesse den jeweiligen (Prozess-)Namespaces zugeordnet (Spalte CID/POD)atopzeigt mehr Daten an, je breiter das Terminalfenster istatopinstallieren (RedHat Linux)# dnf install epel-release # dnf install atop
- Text-grafische Darstellung der Systemauslastung
# atop -B
- Speicher
- Speicherverbrauch-Kennzahlen anzeigen
atop -m
- CPU / Scheduler
- Prozess/Scheduler-Kennzahlen anzeigen
atop -s
- Historische ATOP-Daten
atopkann Daten zur Systemauslastung in eine komprimierte binäre Log-Datei schreiben. Diese Datei kann später gelesen und analysiert werden. Einige Linux-Systeme bringen einen Systemd-Dienst mit, umatopals Dienst im Hintergrund zu starten# systemctl enable --now atop
- Die Logdaten werden nach
/var/log/atop/geschrieben atopLogs lesen (Tasten:t- nächste Daten,T- vorherige Daten,r- Anfang der Datei,Z- Ende der Datei,b- Zeitpunkt eingeben# atop -r /var/log/atop/atop_<datum>
7.3 SELinux
7.3.1 Audit-Subsystem
- SELinux Policy-Verstösse auflisten
# ausearch -m avc
- SELinux Policy-Meldungen der letzten 10 Minuten (weitere
Zeit-Modifikatoren:
this-hour,boot,today,yesterday,this-week,week-ago,this-month,this-year)# ausearch -m avc -ts recent
7.3.2 Do-Not-Edit-Flag
- Die
donotauditRegeln in der SELinux-Richtline ausschalten# semodule -DB
- Um die
donotauditRegel wieder zu aktivieren# semodule -B
7.4 Dateisystem
# df -Th
7.4.1 BTRFS Dateisystem
- BTRFS ist ein "copy-on-write" Dateisystem: kopierte Daten verbrauchen nach dem Kopieren erst einmal keinen Speicher auf dem Storage-Medium.
- Erst nach einer änderung der Daten wird Speicherplatz für das
Delta der Daten verbraucht. Daten auf einem BTRFS Dateisystem können
transparent komprimiert werden, daher kann je nach Inhalt der Daten
mehr der oder weniger Daten auf einem BTRFS Dateisystem
gespeichert werden.
- aus diesem Grund zeigen klassische Unix-Programme wie
du(Disk Usage) oderdf(disk free) auf 'copy-on-write' Dateisystemen nicht die korrekten Werte an und sollte nicht benutzt werden - Für 'copy-on-write' Dateisysteme gibt es spezialisierte Programme, welche die korrekten Daten anzeigen
- aus diesem Grund zeigen klassische Unix-Programme wie
- Die BTRFS Programme installieren
# dnf install btrfs-progs
- Anzeige der Subvolumes eines BTRFS Dateisystems
# btrfs subvol list / ID 256 gen 1157782 top level 5 path home ID 257 gen 1157785 top level 5 path root ID 258 gen 1150812 top level 257 path var/lib/machines ID 259 gen 1148976 top level 257 path swap
- BTRFS "Disk-Free" Kommando
# btrfs filesys df / Data, single: total=309.01GiB, used=296.94GiB System, DUP: total=8.00MiB, used=64.00KiB Metadata, DUP: total=4.00GiB, used=2.08GiB GlobalReserve, single: total=512.00MiB, used=0.00B
- BTRFS "Disk-Use" Kommando
# btrfs filesys du /home
Total Exclusive Set shared Filename
0.00B 0.00B - /home/cas/.mozilla/extensions
0.00B 0.00B - /home/cas/.mozilla/plugins
0.00B 0.00B - /home/cas/.mozilla
1.25MiB 1.25MiB - /home/cas/.cache/mesa_shader_cache/index
0.00B 0.00B - /home/cas/.cache/mesa_shader_cache/34/4791756204dd6c84700e5bdf2a07b2269d87b7
0.00B 0.00B - /home/cas/.cache/mesa_shader_cache/34
0.00B 0.00B - /home/cas/.cache/mesa_shader_cache/e8/e4aab5a6deaa6b3197db45a8049e076dab45b7
8.00KiB 8.00KiB - /home/cas/.cache/mesa_shader_cache/e8/60a3262ad25dd9c8b66cf5d1fe30d5c11f1cfe
4.00KiB 4.00KiB - /home/cas/.cache/mesa_shader_cache/e8/ba73c5504d4da5403d49ff95525360c15e2fee
[...]
- BTRFS Statistiken eines Dateisystems
# btrfs filesys usage /home
Overall:
Device size: 952.28GiB
Device allocated: 317.02GiB
Device unallocated: 635.26GiB
Device missing: 0.00B
Device slack: 0.00B
Used: 301.10GiB
Free (estimated): 647.32GiB (min: 329.69GiB)
Free (statfs, df): 647.32GiB
Data ratio: 1.00
Metadata ratio: 2.00
Global reserve: 512.00MiB (used: 0.00B)
Multiple profiles: no
Data,single: Size:309.01GiB, Used:296.95GiB (96.10%)
/dev/nvme0n1p3 309.01GiB
Metadata,DUP: Size:4.00GiB, Used:2.08GiB (51.89%)
/dev/nvme0n1p3 8.00GiB
System,DUP: Size:8.00MiB, Used:64.00KiB (0.78%)
/dev/nvme0n1p3 16.00MiB
Unallocated:
/dev/nvme0n1p3 635.26GiB