Zabezpeceni mikrosluzby
Pavel Kankovsky
peak na argo.troja.mff.cuni.cz
Sobota Srpen 21 13:21:53 CEST 2021
On Thu, 5 Aug 2021, Jan Kasprzak wrote:
> dotaz na best practices: cim dneska zabezpecujete "neduveryhodny" program?
>
> Konkretne: mam nejakou mikrosluzbu, ktera zpracovava uzivateluv
> (neduveryhodny) vstup. Cilem je zpracovat korektni vstupy, ale nedovolit
> uzivateli, aby neco rozbil, nebo sahal kam nema.
Je trochu rozdíl mezi tím, zda je program nedůvěryhodný (a) ve smyslu, že
ho považuji za podezřelý sám o sobě bez ohledu na to, jaký dostane vstup,
nebo (b) ve smyslu, že nevěřím tomu, že se bude chovat slušně, když
dostane nějaký ošklivý vstup. (I když na variantu (a) lze v jistém smyslu
pohlížet tak, že nedůveryhodným vstupem je kód programu.)
Nebo možná ještě lépe: Je zde otázka, kde lze vytýčit hranici (nebo
hranice, v praxi jich může být víc), na které je možno rozlišit přijatelné
chování od nepřijatelného a vynutit, aby to nepřijatelné nebylo dovoleno.
Škála začíná někde u filtru, který propustí jen nezávadné vstupy, přes
různé úrovně API (typicky syscally, ale může to být i něco na vyšší
úrovni), virtualizaci až fyzickou separaci.
> Priklady:
> - umoznit uzivateli vlozit a vyhodnotit vstup pro bc(1).
> - umoznit uzivateli vlozit TeXovy zdrojak, obrazky, styly, whatever,
> prelozit TeXem podle jeho vyberu, a vratit vystup (PDF, DVI) a pripadne logy
To jsou příklady skoro na opačných koncích škály.
bc relativně jednoduchý program, u kterého by se asi celem snadno dal
udělat filtr na přípustné vstupy, jakož lze i dobře vymezit povolené
chování na úrovni syscallů.
Naopak filtr na TeXové zdrojáky by buď musel vynucovat omezení na velmi
úzkou podmnožinu funkcí, nebo by byl strašně složitý a stejně by bylo
těžké se ujistit, že tam není někde nějaká díra. Na úrovni syscallů to
bude proveditelnější, i když pořád bude nutno dovolit, aby strkal nos
všude možně... naštěstí asi většinou jen pro čtení, horší by bylo, kdyby
chtěl do nějakých sdílených oblastí i zapisovat.
> Historicky jsem s pomerne velkym usilim napsal modul do SELinuxove
> politiky, kterym jsem omezil jak server te mikrosluzby, tak potom zvlast
> ty spoustene programy. Neni to uplne primocare, protoze kdyz je cast
> programu psana ve skriptovacich jazycich (shell, Perl, whatever), tak to
> saha na spousty dalsich veci.
Aby to bylo schůdné, tak je asi potřeba si to trochu zjednodušit.
Za prvé to nedrobit na moc samostatných domén, u kterých by bylo potřeba
řešit přechody mezi nimi. Celé zpracování pokud možno běžet v jedné doméně
(a separaci různých instancí udělat jinak, třeba přes MCS), maximálně
přidat ještě jednu na "server" ve smyslu programu, který zařídí příjem
dat, spustí zpracování a odešle výsledky.
Za druhé je většinou nevyhnutelné se smířit s tím, že přístup pro čtení
k /usr apod. prostě nelze rozumně udělat moc selektivně. A pokud by to mohl
být problém, tak na to vytvořit prostředí (kontejnery, virtualizace), kde
nebude ke čtení nic závadného.
> Zabezpecit treba LibreOffice spoustenou nad Xvfb jsem nakonec
> vzdal, protoze to saha na fakt hodne veci.
>
> U SELinuxu je vyhoda, ze to omezi fakt striktne (modulo chyba v kernelu).
> Nevyhoda je, ze se rozhrani SELinuxu obcas meni, a neni jasne (nebo aspon
> ja to nevim), kde prehledne zjistit vsechny vlastnosti a jejich zmeny
> - jakoze muzu psat
>
> allow server_t soubor_t:file open;
> allow server_t soubor_t:file read;
>
> atd, ale ono existuje i makro
>
> allow server_t soubor_t: file read_file_perms;
To makro se, mimochodem, rozvine tak, že z toho vznikne následující
pravidlo:
allow server_t soubor_t:file { getattr open read lock ioctl };
ale přiznám se, že jsem to vydedukoval tak, že jsem si definici
příslušných maker našel v /usr/share/selinux/devel. ;)
A také je pravda, že seznam těch oprávnění, na která se read_file_perms
rozvine, se v historii trochu měnil. Kdysi dávno tam nebylo open, protože
to oprávnění vůbec neexistovalo a objevilo se až od nějaké verze jádra.
> Podobne existuji vysokourovnova makra pro "toto je PIDfile", "toto je
> vstupni program domeny", a vselijaka dalsi, ktera ale audit2allow neumi
> vyabstrahovat a vypsat.
Teoreticky by se jakási dokumentace rozhraní měla vygenerovat při
kompilaci refpolicy, ale výsledkem je stejně něco jako referenční
příručka.
Občas jsou takové věci zmíněny v nějakých tutoriálech nebo knihách. Já
osobně jsem se ta makra naučil používat tak, že jsem prostě koukal do
refpolicy, napodoboval, co už tam bylo, hledal, jak jsou různé věci
definované a používané atd.
audit2allow má opšnu -R / --reference, která by měla v nějaké míře umět
doporučit vhodná makra z refpolicy. Ale nevím, jak moc dobře to funguje.
> Dalsi moznosti jsou:
>
> AppArmor, s tim nemam moc zkusenosti.
Ani já s tím nemám zkušenosti.
> Jen namespaces: systemd umi pro sluzbu udelat namespaces a rict, ktere
> cesty jsou citelne a ktere i zapisovatelne. Neresi to uplne pristup k
> siti a tak vubec.
Omezení přístupu k souborovému systému asi dělá přes bind mounty, což
není úplně škálovatelné.
> Ruzne opravdove kontejnery (systemd-nspawn, podman, docker, whatever).
> Ja ale nechci mit na disku jeste jednu kopii OS, kterou bych musel zvlast
> udrzovat, a kterou by ta mikrosluzba mela vlastne celou k dispozici.
Kontejnery by AFAICT měly být konstruovány tak, aby se nemusely moc
udržovat.
Pokud kontejner (nebo přesněji jeho image) z nějakého důvodu přestane
vyhovovat, tak by ho mělo být možno zrušit, sestavit automaticky nový
image (třeba s aktualizovaným softwarem) a vyrobit z něj nový kontejner.
Ano, žere to úložný prostor, ale práce nevolníků dobývajících suroviny a
pak z nich vyrábějících nové disky je mnohem levnější než práce adminů a
programátorů. :)
> Navic teda nedavne chyby v kernelu (sequoia nebo jak to nazvali)
> umoznovaly dostat se ven z kontejneru.
Pokud by to v tom kontejneru běželo jen s omezenými privilegii, tak by se
to ven nedostalo. Tedy touto cestou, samozřejmě nelze vyloučit únik jinou
dírou, ale vůči tomu není 100% odolné skoro nic...
> Seccomp - coz by bylo treba kombinovat s namespaces, a odhaduju, ze
> konfigurace by byla podobne zdlouhava jako u toho SELinuxu.
seccomp jsou dvě věci.
Původní seccomp bez přívlastků zakáže skoro všechny syscally a dovolí
procesu pracovat jen s tím, k čemu už má přístup. Je to velmi účinné...
ale také velmi restriktivní a v takovém prostředí mohou fungovat jen
některé programy.
Novější seccomp-bpf umí v podstatě přilepit na syscallové rozhraní
program, který může libovolně blokovat syscally, které se mu nelíbí,
přičemž se může rozhodovat i podle parametrů. Lze s tím udělat dost obecný
sandbox (i když možná jen bezestavový), ale je potřeba mít nějakou
definici toho, co má být povoleno/zakázáno (tomu se nikdy nelze vyhnout),
a nějaký toolchain, který to přeloží do BPF.
> Jak tohle resite? Co se dneska pouziva? Zavrit oci, vybuildovat
> kontejner, poslat do Kubernetu a mit hotovo?
Já podobné problémy naštěstí moc řešit nemusím. ;)
--
Pavel Kankovsky aka Peak "Que sçay-je?"
Další informace o konferenci Linux