Den Dienst Ihres Pakets in einer Jail ausführen: eigenes Konto, kein root, nur das erlaubte Netzwerk
Das Dienstskript eines QPKG-Pakets läuft als root. Mit dem Block Start in a jail des Dienst-Builders laufen die gestarteten Programme unter einem eigenen Konto in einer Sandbox: ohne Capabilities, ohne Möglichkeit, sie zu erlangen, mit einem Filter für gefährliche Systemaufrufe und mit eigenem Netzwerk. Das Beispiel stellt eine Seite bereit, die zeigt, was die Sandbox erlaubt.
- Profilwas läuft und was es sieht
- BlöckeKonto, Ordner, Jail
- Bauenbvs-jail und bwrap sind enthalten
- SignierenFall 1, dann installieren
- Prüfendie Seite zeigt ihre Umgebung
Die Bilder stammen aus Bucket & Code Server IDE 1.0.0-49. Das Beispiel wurde auf einem Test-NAS mit QTS 6.1 gebaut, signiert, installiert und geprüft. Das Konto heißt ola.
01Was die Jail bietet
- Die Dienste laufen unter dem im Profil genannten Konto, niemals als root, ohne Capabilities und mit gesetztem
NoNewPrivs. Ein seccomp-Filter verweigert Mounts, neue Namensräume, Kernelmodule,bpf,io_uring,ptraceund weitere Aufrufe, die Kernel-Exploits nutzen. - Sie sehen die App schreibgeschützt, ihre Datenordner mit Schreibzugriff, eigene
/tmp,/procund/devsowie die glibc des NAS. Keine andere Freigabe, kein/etc/config, kein anderes Paket. - Ihr Netzwerk besteht aus einem eigenen Loopback. Jeder
inbound-Port wird vom NAS an einen internen Port weitergeleitet. Ausgehende Verbindungen laufen über einen HTTP-Proxy, der private Adressen, Loopback-Adressen und die Adressen des NAS verweigert. - Ein Speicherlimit, eine CPU-Gewichtung und ein Prozesslimit gelten für die gesamte Jail.
Das Paket enthält die Jail selbst: bin/bvs-jail und ein statisches bin/bwrap (bubblewrap), die beim Build für jede Architektur bereitgestellt werden.
02Vor dem Start
- Sie brauchen ein mit New project angelegtes QPKG-Projekt, QDK auf der Seite Toolchains und die Builder-Umgebung Ubuntu 24.04. Ihr eigenes App Center erklärt die Einrichtung; dieses Beispiel nutzt die Dienstvorlage Empty.
- Ein Codesignaturzertifikat, das QNAP Ihnen ausgestellt hat, als Dateien. App Center installiert nur signierte Pakete.
03Das Profil
Das Profil ist eine JSON-Datei im Paket. Hier liegt sie im Projekt unter shared/etc/jail/jailbox.json; das Paket installiert sie als etc/jail/jailbox.json in seinem Installationsordner.
# shared/etc/jail/jailbox.json
{
"name": "jailbox",
"user": "jailbox",
"app": "@QPKG_ROOT@",
"data": ["@QPKG_DATA@"],
"services": [
{"name": "checks", "cmd": ["@QPKG_ROOT@/bin/busybox", "sh", "@QPKG_ROOT@/share/jailbox/checks.sh", "@QPKG_ROOT@", "@QPKG_DATA@"], "oneshot": true},
{"name": "web", "cmd": ["@QPKG_ROOT@/bin/busybox", "httpd", "-f", "-p", "127.0.0.1:8080", "-h", "@QPKG_DATA@/www"], "wait_port": 8080}
],
"inbound": [{"listen": "0.0.0.0:19975", "port": 8080}],
"egress": {},
"limits": {"memory_mb": 256},
"stop_seconds": 10
}
@QPKG_ROOT@und@QPKG_DATA@stehen für den Installations- und den Datenordner, deren Pfade erst auf dem NAS feststehen. Bei jedem Start werden sie in einer Kopie aufgelöst, die nur root ändern kann. Die Jail verwendet diese Kopie. Unbekannte Schlüssel werden abgewiesen.appwird schreibgeschützt eingebunden. Hier ist es der gesamte Installationsordner, damit die Dienste die BusyBox des Pakets verwenden können. Eine echte App verweist auf ihren eigenen Verzeichnisbaum, etwa@QPKG_ROOT@/app.serviceswerden der Reihe nach gestartet. Einoneshotläuft zuerst vollständig durch;wait_portwartet auf den lauschenden Dienst, bevor der nächste startet. Mindestens ein Dienst läuft dauerhaft.inboundleitet Port 19975 des NAS an den internen Port 8080 weiter.egressstellt den Diensten unter127.0.0.1:3128einen Proxy für die Ports 80 und 443 öffentlicher Adressen bereit. Eineallow-Liste lässt benannte Ziele unabhängig von ihrer Adresse zu.limits.memory_mbist standardmäßig 2048;stop_secondsgibt an, wie lange die Jail auf das Ende ihrer Dienste wartet.
Der erste Dienst führt dieses ebenfalls im Paket enthaltene Skript aus: shared/share/jailbox/checks.sh. Es schreibt die Ergebnisse der Sandbox-Prüfung in den Ordner, den der zweite Dienst bereitstellt.
#!/bin/sh # Runs inside the jail and writes what the sandbox allows into the page folder. R=$1 D=$2 B=$R/bin/busybox V=$($B dirname "$D") { $B grep -E '^(Uid|CapEff|NoNewPrivs|Seccomp):' /proc/self/status if $B touch "$R/probe" 2>/dev/null; then echo 'write the install folder: allowed'; else echo 'write the install folder: refused'; fi if $B ls /etc/config >/dev/null 2>&1; then echo 'read /etc/config: allowed'; else echo 'read /etc/config: refused'; fi echo "what $V holds here: $($B ls -A "$V" | $B tr '\n' ' ')" echo "network interfaces: $($B tail -n +3 /proc/net/dev | $B cut -d: -f1 | $B tr -d ' ' | $B tr '\n' ' ')" } >"$D/www/checks.txt" echo 'Served from inside the jail.' >"$D/www/index.html"
04Die Blöcke
Auf der Projektseite in der Karte Service and package, Register Blocks: Fügen Sie unter At start mit Add a block fünf Blöcke in dieser Reihenfolge hinzu.
- Data folder on the volume, Name
jailbox: der Ordner$QPKG_DATA. - Create an account, Name
jailbox: das im Profil genannte Konto. - Create a folder,
$QPKG_DATA/www, Eigentümerjailbox:jailbox, Modus750: der einzige Ordner, in den die Dienste schreiben. - Start in a jail, ID
jailbox, Profil$QPKG_ROOT/etc/jail/jailbox.json. Die Wartezeit beim Stoppen muss mindestens dem Wertstop_secondsdes Profils plus 15 entsprechen; der Standardwert 90 reicht hier aus.
- Wait for a port,
19975: Der Start endet, sobald der weitergeleitete Port antwortet.
Unter At a status check prüfen Is it running? mit der ID jailbox und Is the port open? mit 19975 die Jail für den Befehl status des Dienstskripts. Save zeigt die Änderungen jeder Datei; Commit schreibt sie in das Repository des Projekts.
05Bauen, signieren, installieren
Build auf der Projektseite führt qbuild von QDK aus. Das Protokoll nennt die Bestandteile der Jail im Paket.
Ohne Zertifikat wird das Paket unsigniert gebaut. Die Projektseite weist darauf hin, dass Testbereitstellung und Repository ein signiertes Paket benötigen.
- Legen Sie die Zertifikatsdateien
certificate,private_keyundca_certsim Projektordner nebenqpkg.cfgab und bauen Sie erneut: Das Paket ist dann signiert. Die.gitignoreder Vorlage hält die Dateien aus git heraus. In CI stammen sie aus den Secrets des Repositorys, wie Ihr eigenes App Center zeigt. - Installieren Sie das signierte Paket über Test deploy auf der Projektseite (Admin), Install Manually in App Center oder das eigene App-Center-Repository Ihres NAS.
06Die Abschottung prüfen
Öffnen Sie http://<NAS address>:19975/: Über den weitergeleiteten Port erscheint die Seite mit „Served from inside the jail.“. Die benachbarte Datei checks.txt enthält die Ergebnisse des ersten Dienstes:
# http://192.168.1.20:19975/checks.txt
Uid: 222 222 222 222
CapEff: 0000000000000000
NoNewPrivs: 1
Seccomp: 2
write the install folder: refused
read /etc/config: refused
what /share/CACHEDEV1_DATA holds here: .qpkg jailbox
network interfaces: lo
- Der Ordner des Volumes enthält nur die Ordner des Pakets: den Installationsordner unter
.qpkgund den Datenordner. Keine Freigabe, kein anderes Paket. - In einer SSH-Sitzung als Admin zeigt
grep -E '^(Uid|CapEff|NoNewPrivs|Seccomp):' /proc/<pid>/statusfür den Dienst dasselbe. Auch die beiden bubblewrap-Prozesse, die die Jail von außen überwachen, haben keine Capabilities und gesetztesNoNewPrivs, allerdings keinen Filter. - Das Protokoll der Jail liegt als
log/jailbox.logim Datenordner und erfasst jeden Dienststart, dessen Port und das Stoppen. Es vermerkt, wenn der Datenordner root gehört. Die Dienste schreiben nur in den Ordner, den der Block Create a folder dem Konto zugewiesen hat.
07Stoppen, entfernen und verbleibende Daten
/etc/init.d/jailbox.sh stopoder das Stoppen in App Center beendet die Dienste in umgekehrter Reihenfolge. Die Jail protokolliertended (0). Es bleiben weder Prozesse des Kontos noch eine cgroup oder ein lauschender Port zurück.- Das Entfernen des Pakets stoppt die Jail und entfernt den Installationsordner und das Dienstskript. Das Konto und der Datenordner bleiben erhalten, weil kein Block sie entfernt. Your own shell lines unter At removal kann sie ebenfalls entfernen.
- Das Laufzeitverzeichnis der Jail,
/var/run/bvs-jail/jailbox, bleibt erhalten, bis der nächste Start es neu schreibt. Es liegt im Speicherdateisystem von QTS und verschwindet beim nächsten Neustart.