Uruchom usługę swojego pakietu w jailu: osobne konto, bez roota, tylko dozwolona sieć
Skrypt usługi pakietu QPKG działa jako root. Blok Start in a jail w edytorze usług uruchamia programy na osobnym koncie w piaskownicy: bez capabilities i możliwości ich uzyskania, z filtrem niebezpiecznych wywołań systemowych oraz własną siecią. Przykład udostępnia stronę, która pokazuje, na co pozwala piaskownica.
- Profilco działa i co widzi
- Blokikonto, katalogi, jail
- Budowaniebvs-jail i bwrap w pakiecie
- Podpisanieprzypadek 1, potem instalacja
- Sprawdzeniestrona opisuje swoje środowisko
Ilustracje pochodzą z Bucket & Code Server IDE 1.0.0-49. Przykład zbudowano, podpisano, zainstalowano i sprawdzono na testowym NAS-ie z QTS 6.1. Konto nazywa się ola.
01Co zapewnia jail
- Usługi działają na koncie wskazanym w profilu, nigdy jako root, bez capabilities i z ustawionym
NoNewPrivs. Filtr seccomp odrzuca montowanie, nowe przestrzenie nazw, moduły jądra,bpf,io_uring,ptracei inne wywołania wykorzystywane przez exploity jądra. - Widzą aplikację tylko do odczytu, własne katalogi danych do odczytu i zapisu, prywatne
/tmp,/procoraz/dev, a także glibc NAS-a. Żadnego innego udziału, żadnego/etc/config, żadnego innego pakietu. - Ich sieć ma własny interfejs loopback. Każdy port
inboundjest przekierowany z NAS-a na port wewnętrzny. Połączenia wychodzące przechodzą przez proxy HTTP, które odrzuca adresy prywatne, loopback i własne adresy NAS-a. - Limit pamięci, udział CPU i limit procesów obejmują cały jail.
Pakiet zawiera sam jail: bin/bvs-jail i statyczny bin/bwrap (bubblewrap), przygotowywane podczas budowania dla każdej architektury.
02Zanim zaczniesz
- Potrzebne są projekt QPKG utworzony przez New project, QDK na stronie Toolchains i środowisko budowania Ubuntu 24.04. Ich konfigurację opisuje Własne App Center; ten przykład korzysta z szablonu usługi Empty.
- Certyfikat podpisywania kodu wydany Ci przez QNAP, w postaci plików. App Center instaluje tylko podpisane pakiety.
03Profil
Profil to plik JSON należący do pakietu. Tutaj znajduje się w projekcie pod shared/etc/jail/jailbox.json; pakiet instaluje go jako etc/jail/jailbox.json w swoim katalogu instalacyjnym.
# 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@i@QPKG_DATA@oznaczają katalog instalacyjny i katalog danych, których ścieżki są znane dopiero na NAS-ie. Każdy start wpisuje je do kopii, którą może zmieniać tylko root. Jail używa tej kopii. Nieznane klucze są odrzucane.appjest montowane tylko do odczytu. Tutaj to cały katalog instalacyjny, aby usługi mogły używać BusyBoxa z pakietu; rzeczywista aplikacja wskazuje własne drzewo, na przykład@QPKG_ROOT@/app.servicesstartują po kolei. Najpierwoneshotwykonuje się do końca;wait_portczeka, aż usługa zacznie nasłuchiwać, zanim ruszy następna. Co najmniej jedna usługa działa stale.inboundprzekierowuje port 19975 NAS-a na wewnętrzny port 8080.egressudostępnia usługom proxy pod127.0.0.1:3128dla portów 80 i 443 adresów publicznych; listaallowprzepuszcza wskazane cele niezależnie od ich adresu.limits.memory_mbdomyślnie wynosi 2048;stop_secondsokreśla, jak długo jail czeka na zatrzymanie usług.
Pierwsza usługa uruchamia ten skrypt, również zawarty w pakiecie jako shared/share/jailbox/checks.sh. Zapisuje wyniki sprawdzania piaskownicy w katalogu udostępnianym przez drugą usługę.
#!/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"
04Bloki
Na stronie projektu, karta Service and package, zakładka Blocks: użyj Add a block pod At start pięć razy, w tej kolejności.
- Data folder on the volume, nazwa
jailbox: katalog$QPKG_DATA. - Create an account, nazwa
jailbox: konto wskazane w profilu. - Create a folder,
$QPKG_DATA/www, właścicieljailbox:jailbox, tryb750: jedyny katalog, do którego usługi zapisują. - Start in a jail, ID
jailbox, profil$QPKG_ROOT/etc/jail/jailbox.json. Czas oczekiwania przy zatrzymaniu musi wynosić co najmniejstop_secondsz profilu plus 15; domyślne 90 wystarcza.
- Wait for a port,
19975: start kończy się, gdy przekierowany port odpowie.
Pod At a status check bloki Is it running? z ID jailbox i Is the port open? z 19975 sprawiają, że polecenie status skryptu usługi sprawdza jail. Save pokazuje różnice każdego pliku, a Commit zapisuje je w repozytorium projektu.
05Budowanie, podpisanie, instalacja
Build na stronie projektu uruchamia qbuild z QDK. Log wymienia składniki jaila zawarte w pakiecie.
Bez certyfikatu pakiet jest budowany bez podpisu, a strona projektu informuje, że wdrożenie testowe i repozytorium wymagają podpisanego pakietu.
- Umieść pliki certyfikatu
certificate,private_keyica_certsobokqpkg.cfgw katalogu projektu i zbuduj ponownie: pakiet będzie podpisany. Plik.gitignorez szablonu wyklucza je z gita. W CI pochodzą z sekretów repozytorium, jak opisuje Własne App Center. - Zainstaluj podpisany pakiet przez Test deploy na stronie projektu (admin), Install Manually w App Center albo własne repozytorium App Center na NAS-ie.
06Sprawdzenie izolacji
Otwórz http://<NAS address>:19975/: strona wyświetla „Served from inside the jail.” przez przekierowany port. Plik checks.txt obok niej zawiera wyniki pierwszej usługi:
# 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
- Katalog woluminu zawiera tylko katalogi pakietu: instalacyjny pod
.qpkgi katalog danych. Żadnego udziału ani innego pakietu. - W sesji SSH jako admin polecenie
grep -E '^(Uid|CapEff|NoNewPrivs|Seccomp):' /proc/<pid>/statusdla usługi pokazuje to samo. Dwa procesy bubblewrap nadzorujące jail z zewnątrz także nie mają capabilities i mają ustawioneNoNewPrivs, ale bez filtra. - Log jaila to
log/jailbox.logw katalogu danych: start każdej usługi, jej port i zatrzymanie. Log odnotowuje, gdy katalog danych należy do roota; usługi zapisują tylko w katalogu przydzielonym kontu przez blok Create a folder.
07Zatrzymanie, usunięcie i pozostawione dane
/etc/init.d/jailbox.sh stoplub zatrzymanie w App Center kończy usługi w odwrotnej kolejności, a jail zapisujeended (0)w logu. Nie pozostaje żaden proces konta, cgroup ani port nasłuchujący.- Usunięcie pakietu zatrzymuje jail i usuwa katalog instalacyjny oraz skrypt usługi. Konto i katalog danych pozostają, ponieważ żaden blok ich nie usuwa: Your own shell lines pod At removal może usunąć również je.
- Katalog uruchomieniowy jaila,
/var/run/bvs-jail/jailbox, pozostaje do następnego startu, który go nadpisuje. Znajduje się w pamięciowym systemie plików QTS i znika przy ponownym uruchomieniu NAS-a.