Kör paketets tjänst i en jail: eget konto, utan root, bara det nätverk du tillåter
Ett QPKG-pakets tjänsteskript körs som root. Med tjänstbyggarens block Start in a jail körs programmen det startar under ett eget konto i en sandlåda: inga capabilities, ingen möjlighet att få dem, ett filter för farliga systemanrop och ett eget nätverk. Exemplet visar en webbsida som redovisar vad sandlådan tillåter.
- Profilvad som körs och vad det ser
- Blockkonto, mappar, jail
- Byggbvs-jail och bwrap följer med
- Signerafall 1, installera sedan
- Kontrollerasidan beskriver sin miljö
Bilderna kommer från Bucket & Code Server IDE 1.0.0-49. Exemplet byggdes, signerades, installerades och kontrollerades på en test-NAS med QTS 6.1. Kontot heter ola.
01Vad jailen ger
- Tjänsterna körs under kontot i profilen, aldrig som root, utan capabilities och med
NoNewPrivssatt. Ett seccomp-filter nekar monteringar, nya namnrymder, kärnmoduler,bpf,io_uring,ptraceoch andra anrop som kärnexploits använder. - De ser appen skrivskyddad, sina datamappar läs- och skrivbara, egna
/tmp,/prococh/devsamt NAS:ens glibc. Ingen annan delad mapp, ingen/etc/config, inget annat paket. - Nätverket har en egen loopback. Varje
inbound-port vidarebefordras från NAS:en till en intern port. Utgående anslutningar går genom en HTTP-proxy som nekar privata adresser, loopbackadresser och NAS:ens egna adresser. - En minnesgräns, en CPU-vikt och en processgräns gäller för hela jailen.
Paketet innehåller själva jailen: bin/bvs-jail och en statisk bin/bwrap (bubblewrap), som byggsteget förbereder för varje arkitektur.
02Innan du börjar
- Du behöver ett QPKG-projekt skapat med New project, QDK på sidan Toolchains och byggmiljön Ubuntu 24.04. Eget App Center beskriver installationen; exemplet använder tjänstemallen Empty.
- Ett kodsigneringscertifikat som QNAP har utfärdat till dig, som filer. App Center installerar bara signerade paket.
03Profilen
Profilen är en JSON-fil i paketet. Här ligger den som shared/etc/jail/jailbox.json i projektet, och paketet installerar den som etc/jail/jailbox.json i installationsmappen.
# 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@och@QPKG_DATA@står för installations- och datamapparna, vars sökvägar blir kända först på NAS:en. Varje start skriver in dem i en kopia som bara root kan ändra; jailen använder kopian. Okända nycklar nekas.appmonteras skrivskyddad. Här är det hela installationsmappen, så tjänsterna kan använda paketets egen BusyBox; en riktig app pekar på sitt eget katalogträd, till exempel@QPKG_ROOT@/app.servicesstartar i ordning. Enoneshotkörs först färdigt;wait_portväntar tills tjänsten lyssnar innan nästa startar. Minst en tjänst fortsätter att köras.inboundvidarebefordrar NAS:ens port 19975 till port 8080 inuti.egressger tjänsterna en proxy på127.0.0.1:3128för portarna 80 och 443 på offentliga adresser; enallow-lista släpper igenom namngivna mål oavsett adress.limits.memory_mbär 2048 om du inte anger något annat;stop_secondsär hur länge jailen väntar på att tjänsterna ska stanna.
Den första tjänsten kör detta skript, som också ingår i paketet som shared/share/jailbox/checks.sh. Det skriver vad sandlådan tillåter i mappen som den andra tjänsten visar.
#!/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"
04Blocken
På projektsidan, kortet Service and package, fliken Blocks: använd Add a block under At start fem gånger, i denna ordning.
- Data folder on the volume, namn
jailbox: mappen$QPKG_DATA. - Create an account, namn
jailbox: kontot i profilen. - Create a folder,
$QPKG_DATA/www, ägarejailbox:jailbox, läge750: den enda mapp tjänsterna skriver till. - Start in a jail, ID
jailbox, profil$QPKG_ROOT/etc/jail/jailbox.json. Väntetiden vid stopp måste vara minst profilensstop_secondsplus 15; standardvärdet 90 räcker här.
- Wait for a port,
19975: starten slutförs när den vidarebefordrade porten svarar.
Under At a status check gör Is it running? med ID jailbox och Is the port open? med 19975 att tjänsteskriptets kommando status kontrollerar jailen. Save visar varje fils ändringar och Commit sparar dem i projektets arkiv.
05Bygg, signera, installera
Build på projektsidan kör QDK:s qbuild. Loggen anger vad paketet innehåller för jailen.
Utan certifikat byggs paketet osignerat. Projektsidan anger att testinstallation och arkivet kräver ett signerat paket.
- Lägg certifikatfilerna
certificate,private_keyochca_certsbredvidqpkg.cfgi projektmappen och bygg igen: paketet blir signerat. Mallens.gitignorehåller filerna utanför git. I CI kommer de från arkivets hemligheter, som Eget App Center visar. - Installera det signerade paketet: Test deploy på projektsidan (admin), Install Manually i App Center eller NAS:ens eget App Center-arkiv.
06Kontrollera avskärmningen
Öppna http://<NAS address>:19975/: sidan visar ”Served from inside the jail.” via den vidarebefordrade porten. Filen checks.txt bredvid sidan innehåller den första tjänstens resultat:
# 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
- Volymmappen innehåller bara paketets egna mappar: installationsmappen under
.qpkgoch datamappen. Ingen delad mapp, inget annat paket. - I en SSH-session som admin visar
grep -E '^(Uid|CapEff|NoNewPrivs|Seccomp):' /proc/<pid>/statusför tjänsten samma sak. De två bubblewrap-processerna som bevakar jailen utifrån saknar också capabilities och harNoNewPrivssatt, utan filtret. - Jailens logg är
log/jailbox.logi datamappen: varje tjänsts start, dess port och stoppet. Loggen anger när datamappen tillhör root; tjänsterna skriver bara i mappen som blocket Create a folder gav kontot.
07Stopp, borttagning och det som blir kvar
/etc/init.d/jailbox.sh stop, eller stopp i App Center, avslutar tjänsterna i omvänd ordning och jailen loggarended (0). Ingen process för kontot, cgroup eller lyssnande port blir kvar.- När paketet tas bort stoppas jailen och installationsmappen samt tjänsteskriptet tas bort. Kontot och datamappen blir kvar eftersom inget block tar bort dem; Your own shell lines under At removal kan ta bort även dem.
- Jailens körmapp,
/var/run/bvs-jail/jailbox, finns kvar tills nästa start skriver om den. Den ligger på QTS:s minnesfilsystem och försvinner vid nästa omstart.