Nebojte mě, ale vždycky jsem si myslel že setuid po startu služby je povinna operace a nenapadlo by mě, že to některá kritická aplikace (databáze) nemá.
By mě ani ve snu nenapadlo spouštět službu přes su. A její killeni mi automaticky vede na vykřičník v hlavě - tím přece zabíjí to su ne?
BTW: žádná z mých aplikací běžící na Linuxu jako služba k ukončování nepoužívá kill a ani jiné signály. Většinou je místo pidfile socket a tím lze běžící službě možné poslat zprávu včetně žádosti o ukončení. Signály považuji v Linuxu za technologií minulého století
Psal jsem uz v jinem komentari - Kafka je napsana v Jave, je to multiplatformni reseni se stejnou binarkou pro vsechny platformy.
Neni duvod, ani neni technicky mozne, aby si tudiz menila *id.
Ono obecne u programu v nejakem vyssim programovacim jazyce, ktere bezi nad VM / interpretrem, je toto chovani zcela nezadouci, protoze nez se provede zmena *id (napr. v pythonu to jde pomoci platformne specifickeho API z os), tak se pod rootem spusti cely interpretr / VM, takze nez se dostane k dropnuti privs, spusti se spoustu veci, ktere jsou zcela nezadouci, aby bezely pod rootem.
Takze spravne reseni je program rovnou (idealne primo service managerem - systemd, daemon tools,...) spustit pod danym neprivilegovanym uzivatelem.
Dropovani privilegii pomoci seteuid je nebezpecnym legacy hackem, ktery plyne z toho, ze UNIXove systemy mely extremne omezeny security model (root, non-root). A proto i pro pomerne trivialni operace (bind na port < 1024 napr.) bylo nutne spustit binarku pod rootem, ktera nasledne dropne privilegia (a doufame, ze se tak skutecne stane a ze do te doby tam neni nic deraveho v kodu).
Na Linuxu to jde samozrejme mnohem lepe - spustit pod neprivilegovanym userem rovnou a pridat binarce prislusnou capability - napr. pro httpd:
setcap cap_net_bind_service=+ep /usr/sbin/httpd
A pak uz staci httpd spoustet rovnou pod neprivilegovanym uzivatelem (misto spusteni pod roota a doufani), coz je objektivne z pohledu bezpecnosti mnohem lepsi.
Navic tim httpd ziskava jen tuto jednu permission (bindovani na < 1024) a nikoliv absolutni kontrolu nad systemem (spusteni pod rootem).
O tom se nebudu hádat, jako že možnych variant je víc. Přemýšlím kde by dropnuti privilegii mohlo být problematické. Ale dejme tomu no. Druhá část tedy killeni - speciálně Java aplikace se mi taky nepozdava, u aplikaci typu server bych ukončení viděl pomocí requestu. Konečně signály v multithreadove aplikaci je taky pěkná lahůdka
> Přemýšlím kde by dropnuti privilegii mohlo být problematické.
Principialne:
Varianta dropujeme privilegia:
1. Spustim jako root
2. Inicializuji aplikaci
3. V teto fazi muzu napr. natahnout modul do jadra, zapisovat kamkoliv do FS, nainstalovat backdoor, ...
4. Dropnu privilegia
Varianta s posix caps:
1. Spustim jako neprivilegovany uzivatel s nejakym pravem navic (typicky prave ten CAP_NET_BIND - port < 1024)
2. Muzu delat jen to,co mam dovoleno
Nevznika zde tedy to kriticke misto, kdy chvili proces bezi s mnohem vyssimi opravnenimi (nez je dropne) nez skutecne potrebuje.
Takze principialne jsou POSIX Caps. bezpecnejsi (least privilege princip). Nerikam nikde, ze to je nejaka casta chyba, ale principialne mi proste prijde mnohem lepsi nedavat pri startu daemonu napr. pravo nacitat jaderne moduly, kdyz je v zadnem rozumnem pripade nepotrebuje :)
> aplikaci typu server bych ukončení viděl pomocí requestu. Konečně signály v multithreadove aplikaci je taky pěkná lahůdka
Souhlas. Ale i tak tam ty signaly byt musi, protoze to muze napr. nereagovat na request.
Ale zrovna v jave jsou ty signaly vyresene docela dobre - java to zareigstruje, provola shutdown handler, ten potom zada pozadavek na ukonceni vlaken (to si resi Kafka samozrejme sama), takze s tim problem neni.
Problematické je mj. to, že aplikaci nemusíš na 100 % věřit a chceš ji spustit jen pod neprivilegovaným uživatelem, který nemůže škodit ostatním (např. číst a zapisovat v jejich adresářích, firewallem se mu dá omezit síť atd.). Tudíž ta aplikace nesmí být ani na okamžik rootem a měl by to řešit někdo zvenčí (nějaký minimalistický init systém).
Zcela vážně bych chtěl poděkovat za odpověď s nadhledem a za alternativní úhel pohledu.
Off topic: osobně je mi dále trochu proti srsti trend, mít serverovou aplikaci v Javě a horizontálně ji škálovat clusterem kvůli výkonu, ale zjevně "se to tak dneska normálně dělá" a má to své výhody :-) Pick your poison... tohle je úplně jiný doutnající flame, C vs C++ vs všichni ostatní...
Hmm... ono je to v Javě a přitom to má svůj vlastní driver v kernelu pro přímé kopie z fs na netdevice? Asi to přece jenom nebude úplné ořezávátko, a s tou platformovou nezávislostí to taky nebude úplně horké :-)
> osobně je mi dále trochu proti srsti trend, mít serverovou aplikaci v Javě a horizontálně ji škálovat clusterem
No, pokud se bavime o Kafce, tak tam ten cluster neni kvuli Jave, ale kvuli lokalni a vysoke dostupnosti.
Stejne tak u Hadoopu ten cluster neni kvuli Jave, ale kvuli rozdistribuovani dat mezi jednotlive (levne) nody, zajisteni dostupnosti atd.
U tohoto typu softwaru je uplne fuk, zda to je v Jave nebo v C podle me, ta jejich narocnost a pozadavky na deployment vznika uplne z neceho jineho.
> Hmm... ono je to v Javě a přitom to má svůj vlastní driver v kernelu pro přímé kopie z fs na netdevice? Asi to přece jenom nebude úplné ořezávátko, a s tou platformovou nezávislostí to taky nebude úplně horké :-)
Ted jsem asi nepochopil, co ma kernel driver? Kafka je jen message broker, zadne drivery v kernelu nema.
Hmm... ono je to v Javě a přitom to má svůj vlastní driver v kernelu pro přímé kopie z fs na netdevice? Asi to přece jenom nebude úplné ořezávátko, a s tou platformovou nezávislostí to taky nebude úplně horké :-)
A neni mozne ze tim mysli Java NIO (new IO)? To samozrejme nekopiruje data z fs primo na sitovku, ale umi to pouzit mmap a DIRECT_IO, takze to umi obejit OS buffer cache.
"žádná z mých aplikací běžící na Linuxu jako služba k ukončování nepoužívá kill a ani jiné signály. "
To jiste nemusi, ale musi pocitat s tim, ze takovy signal dostane, pokud nepocita, dopadne to presne dle ocekavani - zmrvenejma datama. Protoze kazdej svepravnej tux bere aplikaci nereagujici na kill jako mtrvou a tudiz ji odstreli natvrdo.
Aha, uberblb tvy kategorie samozrejme nemuze tusit, ze normalni system posila sigterm, pak nejakou dobu vycka, a teprve kdyz aplikace (trebas takova co prece signaly neresi) nijak nereaguje, tak ji odstreli killem ze?
Pricemz kazda normalni aplikace pocita s tim, ze i takhle muze bejt ukoncena, a tudiz data nezmrvi, prave proto, ze s tim pocita.
Bez si podat ruce se soudruhem Poetteringem, ten to dela tak, ze tu nereagujici aplikaci necha hnit, mezi tim ukonci sit ... a system na tom zustane viset navzdy.
BTW: žádná z mých aplikací běžící na Linuxu jako služba k ukončování nepoužívá kill a ani jiné signály. Většinou je místo pidfile socket a tím lze běžící službě možné poslat zprávu včetně žádosti o ukončení. Signály považuji v Linuxu za technologií minulého století
Jaký je principiální rozdíl mezi posíláním systémových signálů a vlastních signálů přes vlastní rozhraní? Mi to přijde v principu úplně to samé a je jedno z jakého století to pochází. Aplikaci přijde definovaným rozhraním signál a má se podle toho zařídit...
Ukončení služby je jen jedna z funkcí. Pomocí socketu mohu ke službě nabízet cli. Jak je to těžký nehraje roli, mám na to knihovnu.
Co se týče konzistence dat, tak služba by neměla spoléhat na ukončovací signal a bez něho úmrtí data. To pak ukazuje na špatný návrh. Ideální je, když to přežije výpadek napájení (třeba couchdb má takto zabezpečena data)
Jinak ten můj soket má třeba i schopnost poznat že process opravdu skončil bez nutnosti v cyklu testovat existenci procesu. Když do minuty neskončí, pošle se sigterm což vždycky považuji za equivalent TerminateProcess ve windows. Většinou ho neodchytavam. Většinou ale neukonceni služby na request značí nějaký vážný problém, zpravidla kousle vlákno, takže je dobre začít zjišťovat, co je blbě.
> Ukončení služby je jen jedna z funkcí. Pomocí socketu mohu ke službě nabízet cli. Jak je to těžký nehraje roli, mám na to knihovnu.
cli Kafka ma - viz https://www.cloudera.com/documentation/kafka/latest/topics/kafka_command_line.html
> Co se týče konzistence dat, tak služba by neměla spoléhat na ukončovací signal a bez něho úmrtí data. To pak ukazuje na špatný návrh. Ideální je, když to přežije výpadek napájení (třeba couchdb má takto zabezpečena data)
Souhlas. Ale je to typicky performance trade off - ono ty vypadky / nekorektni ukonceni nejsou moc caste a pokud kvuli nim zbytecne v 99.99% pripadu prichazim o vykon (ktery potrebuji), tak je pochopitelne, ze to muze nekdo navrhnout jinak za cenu toho, ze kdyz uz k tomu nahodou dojde, tak to bude za slusnou vykonovou / jinou penalizaci.
Ono nemusi byt vse ACID complaint (ani databaze, natoz pak message broker), ale je nutne aby to tak bylo zdokumentovano a pouzivalo se to spravne. Kdyz to tak je, je to v nejlepsim poradku.
Pomocí socketu mohu ke službě nabízet cli. Jak je to těžký nehraje roli, mám na to knihovnu.
A není lepší, když je na to jedna knihovna, než když si to musí řešit každá aplikace sama?
Jinak ten můj soket má třeba i schopnost poznat že process opravdu skončil bez nutnosti v cyklu testovat existenci procesu.
Rodičovský proces se to na unixech dozví také, a není na to potřeba ani žádná speciální knihovna.
A není lepší, když je na to jedna knihovna, než když si to musí řešit každá aplikace sama?
Jenže ona na to stejně není jedna knihovna. Zatímco u systemd jsou možné akce jen typu start stop restart reload, tak v rc skriptech pro sysv často byly další akce typu check, list, try, flush a prostě co si tam kdo napsal. Takže bylo jedno rozhraní (service), kde si admin, krom běžných akcí typu start stop, mohl ještě volat další akce specifické pro daný konkrétní program. Tohle systemd neumožňuje, takže krom systemctl jsou ještě u některých programů navíc ještě obslužné skripty, kde je to, co bylo před tím dostupné i přes service. Takže v tomto ohledu se nic nevylepšilo.
Vylepsilo, protoze sluzba nemusi resit jak se ma spustit, nemusi resit dropovani privilegii, nemusi se v ni konfigurovat logging (zvlast u jednodussich sluzeb), funguje to jak v spravci sluzeb, tak treba v dockeru.
A je treba rozdelit:
1) Spousteni / zastaveni sluzeb - coz je odpovednost spravce sluzeb
2) Akce ve sluzbe - na coz muzu mit CLI program, pokud ho dana sluzba potrebuje (spousta sluzeb nepotrebuje, jine sluzby zase potrebuji tyto akce mit dostupne jako REST, jine z command line, moznosti je mraky...)
Ten logging bych dvakrát nezmiňoval. Protože pokud chce služba logovat do souboru někam k sobě přesměrováním standardního výstupu, jediná možnost je spouštět ji přes shell, což není zrovna optimální.
Takže nakonec to musí zase řešit služba sama. A přitom by stačilo přidat jednu konfigurační položku, vedle těch stávajících. Místo toho raději integrujeme DNS, web server, NTP a plno dalších hovadin.