Ehh... spousta tradičních démonů má v konfiguráku řádek nebo dva, pod jakým uživatelem a skupinou má běžet. Spustí se klidně jako root, pozotvírá co potřebuje (a může jenom pod rootem) a vzápětí sám provede setuid. Například:
http://www.proftpd.org/docs/howto/ConfigFile.html#Identity
V uvedeném popisu je dále rozlišován "skutečný" uživatel/skupina vs. "efektivní" uživatel/skupina - tato nuance je mimo moje dosavadní poznání, jenom na ni upozorňuji protože mě zaujala.
Další documentace:
http://man7.org/linux/man-pages/man2/setuid.2.html
http://man7.org/linux/man-pages/man2/setgid.2.html
http://man7.org/linux/man-pages/man2/seteuid.2.html
...atd
= kdyby to kafka řešila sama, není co řešit zvenčí.
Proc by to mela resit Kafka?
Kafka to neresi, stejne jako vsechny ostatni multiplatformni reseni, ktere si nechteji zanaset kod platformne zavislymi volanimi (navic Kafka je v Jave, takze tam volani set*id neni k dispozici z duvodu, ze Java obecne platformne specificke API nepodporuje - coz je dobre).
Jenže změna uživatele je přesně to, co Kafka, web server, databázový server ani jiná služba dělat nemá. Starat se o to má právě správce služeb. Je zajímavé, jak odpůrci systemd (zrovna v tomhle vlákně tedy nejsou) vždy mluví o unixovém principu, kdy jeden program dělá jen jednu věc, a pak přijdou s tím, že webový server samozřejmě má nastavit limity, nastavit cgroups, zbavit se zbytečných capabilities, změnit uživatele, odpojit se od terminálu, logovat – jo a když bude mít čas, mohl by taky servírovat nějaké webové stránky.
A taky se o to prakticky kazdy spravce sluzeb stara, krome techto starych sysv-like initu...
Ale jinak naprosty souhlas, tohle je presne odpovednost spravce sluzeb.
A kdyz se tento princip dodrzuje, tak pak napr. taky daemon dobre funguje v kontejnerech - protoze dela jen presne to, co ma a neresi blbosti, co nema (a ktere za nej muze resit docker - napr. zmenu uid, o logovani ani nemluve).
To není 100% pravda. Například web-server na běžném OS pořebuje privilegium poslouchat na portu 80 (tedy menším než 1024). Takže musí nejdřív začít poslouchat a potom změnit uživatele. Pokud ovšem za něj začne poslouchat správce služeb, tak se najednou musí správce služeb postarat, aby ta socketa měla nastavené vše co ten webserver potřebuje a musí rozumět síťovému stacku*. Spousta dalších služeb také potřebuje privilegovaný přístup k nějakým dalším prostředkům, ale jinak běžet neprivilegovaně. To se nejlépe řeší tím, že se jim poskytne API/ABI. Zvenčí to chce jen zajistit aby ta služba neměla přístup k věcem ke kterým mít přístup nemá. Na to mi v tradičním systému stačí code-review kódu před vzdáním se rootovských práv.
* tohle autoři systemd řeší pomocí socket-activation. Pak ale nastavím socket-activation službu a nevím, že je služba rozbitá, dokud se doopravdy něco nepokusí přistoupit na tu socketu. V produkčním prostředí děkuji, ale nechci.
To není 100% pravda. Například web-server na běžném OS pořebuje privilegium poslouchat na portu 80 (tedy menším než 1024). Takže musí nejdřív začít poslouchat a potom změnit uživatele.
To není pravda. Buď může mít proces capability pro naslouchání na privilegovaném portu, nebo mu může příslušný socket předat správce služeb.
Pak ale nastavím socket-activation službu a nevím, že je služba rozbitá, dokud se doopravdy něco nepokusí přistoupit na tu socketu.
To platí jedině v případě, kdy je ta služba odfláknutá. Když se ta služba bude chovat aspoň trochu rozumně, tak se v případě problémů ukončí.
A k čemu mi je správné ukončení když se ta služba ani nespustí? Já potřebuju aby ta služba byla funkční, což se nahrazením kofiguráků a případným reloadnutím systemd nedozvím, protože ke skutečnému spuštění a tedy přeparsování konfiguráků služby a vyhlášení chyby dojde až s prvním přístupem na socketu.
@Jirsak 19:44:
rika se nekrm trolla, ale nemuzu si pomoct:
nezodpovedny package maintainer prehodil sshd v debianu na systemd unitu forking. Tim ale vyradil kontrolu toho, ze sshd bude umet vytvorit listening socketu na portu 25. Systemctl (re)start sshd tvril ze je vse v poradku. Nicmene sshd nebezelo.
> nezodpovedny package maintainer prehodil sshd v debianu na systemd unitu forking. Tim ale vyradil kontrolu toho, ze sshd bude umet vytvorit listening socketu na portu 25. Systemctl (re)start sshd tvril ze je vse v poradku. Nicmene sshd nebezelo.
To je neprijemne. Ale jako je to poznatek na urovni toho, ze kdyz udela package maintainer krpu, muze to rozbit system. Stejne tak se dalo udelat milion jinych problemu v sysv initu. To je neresitelny problem.
> To je neprijemne. Ale jako je to poznatek na urovni toho, ze kdyz udela package maintainer krpu, muze to rozbit system. Stejne tak se dalo udelat milion jinych problemu v sysv initu. To je neresitelny problem.
Pouze do te doby, dokud je sam. V Debian Jessie je ale vadnych vice nez polovina service filu (subjektivni mereni, vychazejici z toho, ze 90% sluzeb ktere pouzivame ma v Debian jessie spatny service file, vetsinou to nevadi a naucili jsme se s tim zit, ale v nekterych pripadech to vede k jeste horsim chybam.)
> To není 100% pravda. Například web-server na běžném OS pořebuje privilegium poslouchat na portu 80 (tedy menším než 1024). Takže musí nejdřív začít poslouchat a potom změnit uživatele. Pokud ovšem za něj začne poslouchat správce služeb, tak se najednou musí správce služeb postarat, aby ta socketa měla nastavené vše co ten webserver potřebuje a musí rozumět síťovému stacku*. Spousta dalších služeb také potřebuje privilegovaný přístup k nějakým dalším prostředkům, ale jinak běžet neprivilegovaně. To se nejlépe řeší tím, že se jim poskytne API/ABI. Zvenčí to chce jen zajistit aby ta služba neměla přístup k věcem ke kterým mít přístup nemá. Na to mi v tradičním systému stačí code-review kódu před vzdáním se rootovských práv.
Proc to delat dobre, kdyz to jde delat uplne blbe, ze :)
Navic to neni absolutne pravda, existuje mnohem lepsi reseni (a dokonce nekolik) - pridat procesu capability (napr. poslouchat na privilegovanem portu), pak zadne prava roota nepotrebuje a muze bezete rovnou pod neprivilegovanym uzivatelem.
Doporucuji dostudovat POSIX Capabilities, je to docela uzitecne :)
Druhou moznosti je socket activation, ale to je trochu na neco jineho.
> * tohle autoři systemd řeší pomocí socket-activation. Pak ale nastavím socket-activation službu a nevím, že je služba rozbitá, dokud se doopravdy něco nepokusí přistoupit na tu socketu. V produkčním prostředí děkuji, ale nechci.
Socket activation totiz neni primarne urceny na reseni poslouchani na portu < 1024, ale pro sluzby, ktere nemaji bezet porad, ale jen tehdy, kdyz jsou potreba :) A samozrejme to ma dusledek ten, ze se ... sluzba spustti az tehdy, az je potreba.
Pro permanentne bezici sluzby je to nevhodne.
Btw, nemas na produkci healthcheck a monitoring? Spolehat na to,ze sluzba funguje, kdyz bezi proces - diky, ale to bych nechtel :)
> Btw, nemas na produkci healthcheck a monitoring? Spolehat na to,ze sluzba funguje, kdyz bezi proces - diky, ale to bych nechtel :)
Samozřejmě, že mám. Jen poukazuju na to, že na produkci vnáší socket-activation výrazně větší složitost do orchestračních nástrojů, protože když se orchestrační nástroj nedozví okamžitě, že tam nahrál syntakticky špatný konfigurák, tak se z používání takového orchestračního nástroje administrátor téměř okamžitě zblázní.
> Samozřejmě, že mám. Jen poukazuju na to, že na produkci vnáší socket-activation výrazně větší složitost do orchestračních nástrojů, protože když se orchestrační nástroj nedozví okamžitě, že tam nahrál syntakticky špatný konfigurák, tak se z používání takového orchestračního nástroje administrátor téměř okamžitě zblázní.
Tak ho nepouzivej, je to feature primarne pro desktop a obcas bezici sluzby :) Na permantne bezici sluzby to neprinasi temer zadne vyhody.
Je to stejna situace jako za davny casu s inetd - uplne ten stejny problem, uplne ty stejne issues, to je dane principem celeho reseni.
> Zmena uzivatele je dostupna snad na vsech platformach, kde java bezi. A tam kde ne, to java muze resit stejne jako treba nedostupnost site nebo grafickyho prostredi, coz jsou samozrejme taky plaforme zavisly veci, ktery java musi resit jako spoustu dalsich platforme zavislych veci.
A proc by to mela resit ? Ono to otvira spoustu problemu - kdyz muzu zmenit na jine (E)UID, je EUID vzdy k dispozici? Nebo mam menit UID? Co kdyz to chci podle jmena uzivatele - je potreba pridat API pro pristup k databazi uzivatelu?
Takze ne, takove veci do Javy opravdu nepatri, tam patri cross platform API.
Navic krome starickeho sysvinitu (a stare verze upstartu) to vsechny platformy podporuji - systemd, openrc, launchd (MacOS), Windows Service Host (ci jak se to tam jmenuje) to umi...
Tohle by si program/služba nikdy neměl řešit sám – programy/služby by měly být navzájem izolované, aby nemohly ovlivnit data jiných programů/služeb/uživatelů. Ostatně proto je to víceuživatelský systém – jednotliví uživatelé by měli mít možnost si víceméně prasit, co chtějí, ale systém by se měl postarat o to, aby neohrožovali jiné uživatele.
Pod rootem by toho mělo běžet naprosté minimum a jen to, čemu můžeš věřit – tzn. měl bys mít možnost si stáhnout z internetu / mimo distribuci nějakou aplikaci, které nemusíš až tak úplně věřit, založit jí uživatelský účet a spouštět ji pod ním, aniž by ses musel bát, že ti poškodí zbytek systému – což znamená, že ta aplikace nikdy nesmí mít práva roota.
Pak je ovšem potřeba vymyslet systém práv, který dovolí otevřít poslouchání na TCP portu 80 třeba jen uživateli www-data, nedej bože, že bych chtěl aby na každou IP systému (která může být přidělena dynamicky) byl pro port 80 jiný povolený uživatel. A spousta podobných věcí. Není to nemožné, jen je to spousta práce, a výrazné přepsání současného systému oprávnění. Pokud se nechá řízení na aplikaci, tak alespoň víte, že nevyvíjíte něco co nakonec třeba ani nikdo nepoužije.
Pak je ovšem potřeba vymyslet systém práv, který dovolí otevřít poslouchání na TCP portu 80 třeba jen uživateli www-data
Systém práv na to není potřeba vymýšlet – řeší se to tak, že že správce služeb má práva root a, zbaví se ostatních capabilities mimo CAP_NET_BIND_SERVICE, přepne se na uživatele www-data a pak nahradí proces procesem webového serveru.
> Není to nemožné, jen je to spousta práce,
Spousta prace to asi byla takovy system vytvorit, nemam nejmensich pochyb, ze behem vyvoje kernelu 2.1 nekdy v roce 1998 se na tom vyvojari nadreli :-)
Od kernelu 2.2 (vydan v roce 1999) mame capabilities, ktere presne tohle umoznuji - viz man 7 capabilities. Od kernelu 2.6 (rok 2003) se neda z kernelu jejich podpora ani vypnout.
Ano máme. A jsou linux-specifické. Takže tam kde jsme měli portabilní programy (SysV není jen linuxová záležitost), tak se nic nezměnilo (alespoň dokud se nenašel někdo komu by se to chtělo portovat). A tam kde programy portabilní nebyly tak je to jedno, stejně mají linux specifický kód. Jesli se v něm volá libdaemonize nebo libsystemd je mi šumák.
Zatraceně, vytratila se mi pointa. A navíc jsem si tu manpage přečetl napoprvé špatně, protože je ta manuálová stránka napsaná tak aby bylo jasné jak se řeší SUID bit na souboru. Tady jsme ale v jiné situaci.
Přijde mi, že capabilities je pěkný systém jak udělat hardening, ale stále mi nerozliší, že uživatel www-data-4 smí poslouchat jen na 1.2.3.4:80 a uživatel www-data-5 jen na 1.2.3.5.80. Takže stále musím věřit aplikaci, že si vezme ten správný resource. A pokud neobsahuje linux-specifický kód tak se práva CAP_NET_BIND_SERVICE umí vzdát jen jediným způsobem: změnou uživatele z roota na neroota. Vůbec se neodvažuji tady pomyslet na aplikace, které se práv po inicializaci nevzdají, jen proto, že "už jich přece nemají tolik, tak proč to řešit".
Pokud budete chtít z tohoto důvodu CAP_NET_BIND_SERVICE aplikaci vůbec nedat, potřebujete aby váš init systém uměl rozumět prostředkům, které té službě předává (listen socketa na port 80), to už není moc KISS, a vždy přijde někdo s další třídou prostředků, které je do toho potřeba doimplementovat. Tohle by bylo hezké, kdyby to bylo řešeno jako obecná rozšiřitelnost, a ne jen řešení jednoho konkrétního případu (síťový subsystém).
Pokud bude mít aplikace linux-specifický kód, starající se o inicializaci (zahození CAP_NET_BIND_SERVICE), tak už mě neuráží, že se má starat i o to, aby správně běžela v historickém sys-V initu. A pokud pak systemd vyžaduje jinou sekvenci spouštění, má ji vyžadovat, místo toho aby tvrdil, že takovou aplikaci (napsanou pro sysV) umí spustit bez ztráty spolehlivosti spuštění.
Vůbec se neodvažuji tady pomyslet na aplikace, které se práv po inicializaci nevzdají, jen proto, že "už jich přece nemají tolik, tak proč to řešit".
Právě proto je dobré mít moderního správce služeb. Pak v té aplikaci nemusíte mít žádný kód specifický pro linux, nespouštíte jí pod rootema nemusíte se spoléhat na to, že se vzdá práv. Prostě jí spustíte pod správcem služeb, který se vzdá nepotřebných capabilit, změní uživatele a pak svůj proces nahradí procesem služby.
potřebujete aby váš init systém uměl rozumět prostředkům, které té službě předává (listen socketa na port 80)
Ne, nepotřebujete, viz popis výše. Už to tu popisuju podruhé, tak to snad konečně vezmete na vědomí.
@Jirsak 19:42
> Ne, nepotřebujete, viz popis výše.
Tak teď si přímo protiřečíte. Pokud nerozumí prostředkům, tak se nemůže vzdát capabilit na získání těch prostředků, a pak spustit aplikaci. Jak by se ta aplikace k těm prostředkům dostala? Buď nechá capability na získání těch prostředků aplikaci, ať se jich vzdá sama po inicializaci, nebo umí ty prostředky pro tu aplikaci obstarat. Pokud je umí obstarat, tak jim rozumí.
ebik, 19:57: Jenže on se nevzdává capabilit pro získání těch prostředků, vzdává se všech ostatních capabilit. Že by se vzdal i té capability pro získávání potřebných prostředků je velmi výjimečný případ a linux pro to holt prostředky neposkytuje. Asi by se to využilo jen pro tu capabilitu naslouchání na privilegovaných portech, navíc u aplikací, u kterých není možné obnovit konfiguraci za běhu. Navíc chyba, že by aplikace začala nečekaně naslouchat někde, kde nemá, je dost nepravděpodobná a ne moc nebezpečná.
@Jirsak, 20.1. 21:21
> Že by se vzdal i té capability pro získávání potřebných prostředků je velmi výjimečný případ
Tak to ani omylem. Většina serverů co znám, tak má master proces, který jenom spawnuje "workery" (nebo jen jednoho workera). Ten master server si ponechává roota a získává prostředky, a ty workeři již na získání dalších prostředků práva nemají.
>Navíc chyba, že by aplikace začala nečekaně naslouchat někde, kde nemá, je dost nepravděpodobná a ne moc nebezpečná.
Nebezpečné je pokud se aplikace (díky například buffer overflow nebo underrun) zmocní útočník. Může aplikaci přinutit poslouchat třeba na portu 22 (pokud předtím odstřelil ssh, třeba oom killem) jen proto, aby získal víc času. Nebo na nějakém jiném portu (třeba na portu LDAPu, aby odchytil přihlašovací hesla do legacy systémů napojených na LDAP). A zrovna třeba webservery jsou tak častým případem serverů, že někdo neustále hledá nějakou jejich zranitelnost.
> Zapoměl jsem dopstat, že master proces se stará pouze o konfiguraci a inicializaci. Takže je jen malá šance, že ho chyba ve workeru nějak ovlivní. Naopak workeři dělají veškerou práci, takže téměř celý attack surface je na workerech a ne na masterovi.
Porad mnohem vetsi nez pokud ten maste proces ty root prava vubec nema.
Takze attack surface je zde mnohem vetsi nez v pripade, ze master proces pod rootem nebezi, ma jen extra cap na poslouchani. A pokud se k tomu prida SELinux policy, ktera omezi na kterych portech muze poslouchat, tak tu tenhle attack surface mizi uplne.
> Tak to ani omylem. Většina serverů co znám, tak má master proces, který jenom spawnuje "workery" (nebo jen jednoho workera). Ten master server si ponechává roota a získává prostředky, a ty workeři již na získání dalších prostředků práva nemají.
Jop, presne, ponechava si roota, protoze .... musi :-D A ten mu zustane, takze jakakoliv chyba tam je skutecne zasadni prusvih (protoze child procesy typicky s master procesem nejak komunikuji).
S capabilities se tam root vubec neobjevi, tudiz moznosti zneuziti jsou vyrazne mensi (navic muze mit capabilities opravdu hodne osekane, tudiz nemusi mit ani ty standardne dostupne pro neprivilegovaneho uzivatele).
> Nebezpečné je pokud se aplikace (díky například buffer overflow nebo underrun) zmocní útočník. Může aplikaci přinutit poslouchat třeba na portu 22 (pokud předtím odstřelil ssh, třeba oom killem) jen proto, aby získal víc času. Nebo na nějakém jiném portu (třeba na portu LDAPu, aby odchytil přihlašovací hesla do legacy systémů napojených na LDAP). A zrovna třeba webservery jsou tak častým případem serverů, že někdo neustále hledá nějakou jejich zranitelnost.
Zase, tohle resi SELinux policy. Pak muze daemon poslouchat jen na tech portech, na ktere ma skutecne pravo a na zadnem jinem.
> Jop, presne, ponechava si roota, protoze .... musi :-D
Musely v dobe pred capabilities. Bylo by ale demenci toto chovani (vzdani se prav ve workerovi) zahodit, kdyz uz je to jednou napsane. Navic to ze ma aplikace roota, NEZNAMENA, ze ma vsechny capabilities. Pokud jsem cetl manualovou stranku dobre, tak se lze snadno JAKO ROOT vzdat nekterych capabilities (a nemoct je pak ziskat zpet), a naopak zmenou uzivatele na neroota prijdu o VSECHNY capabilities, ktere normalni uzivatel nema (i pravo poslouchat na portu 80).
ebik 9:24: proč tu pořád opakujete ty vaše nesmysly, když vám tu minimálně dva lidi vysvětlili, jak to je? Tak ještě jednou. S moderním správcem služeb to funguje tak, že správce služeb vytvoří pod rootem nový proces (stále je to proces správce služeb), ten se následně zbaví nepotřebných capabilit, nastaví limity, změní uživatele na neprivilegovaného a na závěr proces nahradí procesem spouštěné služby. Proces spouštěné služby se tedy spouští pod neprivilegovaným účtem a práva roota nikdy nemá, má např. capabilitu pro naslouchání na privilegovaném portu (pokud ji správce systému v konfiguraci té služby povolil) a o capabilities nemusí vědět vůbec nic. Poku do nich něco ví, může se při spouštění workeru vzdát i té capability pro naslouchání na privilegovaném portu.
Takže rozdíl v tom vašem přístupu a přístupu moderních správců služeb je v tom, že vy spouštíte řídící proces s právy roota a doufáte, že se jich alespoň při spuštění workeru vzdá, zatímco moderní správce služeb spustí i ten řídící proces s omezenými právy. Přestaňte tedy prosím pořád vykládat o tom, jak je strašně výhodné spouštět proces s právy roota, i když je vůbec nepotřebuje. Výhodné to není, je to nebezpečné.
> Ano máme. A jsou linux-specifické. Takže tam kde jsme měli portabilní programy (SysV není jen linuxová záležitost), tak se nic nezměnilo (alespoň dokud se nenašel někdo komu by se to chtělo portovat). A tam kde programy portabilní nebyly tak je to jedno, stejně mají linux specifický kód. Jesli se v něm volá libdaemonize nebo libsystemd je mi šumák.
Linux specificke? Proc se jim rika POSIX Capabilities tedy? Ano, puvodni POSIX draft 1003.1e je stazeny, ale tj celkem fuk, Linux neni jedina implementace.
Navic i kdyby byla, je to jedno, viz nize.
> Přijde mi, že capabilities je pěkný systém jak udělat hardening, ale stále mi nerozliší, že uživatel www-data-4 smí poslouchat jen na 1.2.3.4:80 a uživatel www-data-5 jen na 1.2.3.5.80. Takže stále musím věřit aplikaci, že si vezme ten správný resource. A pokud neobsahuje linux-specifický kód tak se práva CAP_NET_BIND_SERVICE umí vzdát jen jediným způsobem: změnou uživatele z roota na neroota. Vůbec se neodvažuji tady pomyslet na aplikace, které se práv po inicializaci nevzdají, jen proto, že "už jich přece nemají tolik, tak proč to řešit".
Na tohle neslouzi caps, ale selinux policy, ta presne resi, ze program X muze poslouchat na portu Y a zadnem jinem.
> Pokud budete chtít z tohoto důvodu CAP_NET_BIND_SERVICE aplikaci vůbec nedat, potřebujete aby váš init systém uměl rozumět prostředkům, které té službě předává (listen socketa na port 80), to už není moc KISS, a vždy přijde někdo s další třídou prostředků, které je do toho potřeba doimplementovat. Tohle by bylo hezké, kdyby to bylo řešeno jako obecná rozšiřitelnost, a ne jen řešení jednoho konkrétního případu (síťový subsystém).
Vubec ne, zakladem je to, ze program pod root uzivatelem vubec nespustim, spustim ho jako neprivilegovany uzivatel (tzn. to, kam se dostane bezny sysv daemon) + navic mu dam urcite specificke caps navic. A nebo mu caps i normalniho neprivilegovaneho uzivatele jeste odeberu.
> Pokud bude mít aplikace linux-specifický kód, starající se o inicializaci (zahození CAP_NET_BIND_SERVICE), tak už mě neuráží, že se má starat i o to, aby správně běžela v historickém sys-V initu. A pokud pak systemd vyžaduje jinou sekvenci spouštění, má ji vyžadovat, místo toho aby tvrdil, že takovou aplikaci (napsanou pro sysV) umí spustit bez ztráty spolehlivosti spuštění.
Prave ze ta aplikace nemusi mit vubec zadny linux specific kod. Muze byt napsana v ANSI C, stejne zdrojaky muzou fungovat na FBSD, Linuxu, Windows, Darwinu, ....
Proste a jenom se udela .service, v ni definuje pod jakym uzivatelem to ma bezet, prip. jak se omezi capabilities (prip pridam dalsi caps na binarku pres setcap). A ten program se nemusi starat vubec o nic. Je to lepsi, bezpecnejsi a jednodussi.
> Pokud bude mít aplikace linux-specifický kód, starající se o inicializaci (zahození CAP_NET_BIND_SERVICE), tak už mě neuráží, že se má starat i o to, aby správně běžela v historickém sys-V initu. A pokud pak systemd vyžaduje jinou sekvenci spouštění, má ji vyžadovat, místo toho aby tvrdil, že takovou aplikaci (napsanou pro sysV) umí spustit bez ztráty spolehlivosti spuštění.
No a nebo se toho prava nevzda. S nastavenim caps v serivce nemuze v systemu nic, diky SELinuxu muze akorat znovu... poslouchat na svem portu :)
A nezasvini se kod platformne specifickymi vecmi.
Jednoznacn mnohem lepsi reseni nez to, co delaji daemony diky sysv - seteuid (cimz se rozhodne nezbavi vsech caps, ale pouze tech, ktere jsou navic dane root uzivateli oproti jinemu).