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