Sziasztok kollégák,
múlt héten kicsit elszaladt velem a paci és újraírtam egy projektet amit régesrégen már egyszer megcsináltam: egy olyan SSH szerver ami Docker containereket vagy Kubernetes podokat indít.
A cél az hogy a user SSH-zva közvetlenül a konténerben kössön ki mindenféle shellout és egyéb huncutságok nélkül. Ezt aztán lehet használni pl. webhostinghoz ahol a userhez tartozó site-ok a containerbe vannak mountolva a permission mátrixnak megfelelően, honeypotnak vagy egyéb érdekes és izgalmas dolgokra.
Hogy dinamikusan confolható legyen az egész cucc az autentikációt valamint a container környezet konfigurálását egy külső szolgáltatáson keresztül végzi.
Most hozzátok a kérésem: üssétek, nyomkodjátok, találjatok benne bugokat.
- Forráskód: https://github.com/janoszen/containerssh
- Quick start Docker környezetre: https://github.com/janoszen/containerssh/tree/master/example
- Cikk hogy hogyan működik: https://pasztor.at/blog/ssh-direct-to-docker
Köszönöm a segítségeteket!
Update: megjelent a 0.1.0-s verzió
- 3530 megtekintés
Hozzászólások
Ket kerdes:
- Tamogajta-e ez a megoldas, hogy a usernek legyen egy fix containere, amibe periodikusan be tud lepni? (Ilyen pl az emlitett webhosting eseten a hosting environment, ahonnan kiszolgalunk, de pl egy SSH kapcsolat szakadas utan se lenne rossz bizonyos timeouton belul visszaterni tudni az elozo feladathoz (mint egy okos screen/tmux))
- Kilepes/kapcsolatbontas utan gondoskodik-e a garbage collectionrol, vagyis a mar nem hasznalt kontenerek elpusztitasarol?
- A hozzászóláshoz be kell jelentkezni
Tamogajta-e ez a megoldas, hogy a usernek legyen egy fix containere, amibe periodikusan be tud lepni? (Ilyen pl az emlitett webhosting eseten a hosting environment, ahonnan kiszolgalunk, de pl egy SSH kapcsolat szakadas utan se lenne rossz bizonyos timeouton belul visszaterni tudni az elozo feladathoz (mint egy okos screen/tmux))
Jelenleg nem, bár gondolkoztam egy "dockerexec" illetve "kubeexec" backenden ami pont ezt valósítja meg. A webhosting környezetnél ez annyira nem szempont. (A ContainerSSH egy elődje pont webhostingot szolgált ki és soha nem volt erre panasz.) A nehézség itt az hogy Kubernetes környezetben a pod adott esetben átkerül máshová amitől a state nem marad meg.
Kilepes/kapcsolatbontas utan gondoskodik-e a garbage collectionrol, vagyis a mar nem hasznalt kontenerek elpusztitasarol?
Félig. Jelenleg ha megszakad a kapcsolat akkor eltakarítja a containert azonnal. Ha a ContainerSSH maga pusztul meg akkor erre sajnos még nem képes, és még nem is egészen tudom hogy hogyan oldom meg mivel a config szerver dinamikusan adhat át configot, tehát a ContainerSSH eleinte adott esetben nem is tudja hogy hova fog csatlakozni.
- A hozzászóláshoz be kell jelentkezni
Ez egy nagyszerű dolog! Synology NAS-ra megpróbálom felrakni.
- A hozzászóláshoz be kell jelentkezni
Elvben működnie kell. Jelenleg csak x86-ra van fent a Docker hubon de semmi nem szól az ellen hogy lefordítsd másra ha esetleg kisebb Synologyd van.
- A hozzászóláshoz be kell jelentkezni
x86 elég, mert arra van official docker, míg kisebb synologykra nincs sajna.
- A hozzászóláshoz be kell jelentkezni
Kuberneteses use case-t hogy képzeljem el, hol futna ez a szolgáltatás? Külön valami frontend szerveren, vagy k8s PODként? Utóbbi esetben a service exposure kicsit problémás lehet (NodePort)
Az embert 2 éven át arra tanítják hogyan álljon meg a 2 lábán, és hogyan beszéljen... Aztán azt mondják neki: -"Ülj le és kuss legyen!"..
- A hozzászóláshoz be kell jelentkezni
Mindkettő működik. Vagy NodePort-tal expose-olod, vagy pedig load balancer erőforrás mögé rakod. Ha a host key-t secretben tárolod akkor semmi nem szól az ellen hogy akár több példányt futtass belőle.
Megpróbálok belőle összerakni valami Kubernetes YAML filet ami példaszerűen deployolja, hátha úgy egyszerűbb lesz.
- A hozzászóláshoz be kell jelentkezni
Szia!
Nagyon király! Ment a csillag.
Nekem csak a Docker nem tetszik benne. Sokkal nyugodtabb vagyok, amikor nem kell egy root joggal futó szupercsillagharcos daemon-hoz kötnöm magam.
Valamelyik Red Hat alternatíván, pl. Podman-en gondolkoztál már? Nekem nagyon bevált.
(A docker debug kurzusodból pár éve nagyon sokat tanultam, hatalmas köszi érte!!!)
"If I had six hours to chop down a tree, I'd spend the first four hours sharpening the axe."
- A hozzászóláshoz be kell jelentkezni
Nem kötelező Dockert használni, használhatsz Kubernetest is. A k3s pl. könnyebben települ mint a Docker. Kubernetessel tudsz pod- és network security policyt tenni rá.
A Podmannel az a baj hogy nincs HTTP API-ja (mivel ugye nincs daemon), így ha beépítem a Podman támogatást az csak és kizárólag Linuxon fog működni. Lehetne build flagekkel trükközni de ez jelenleg elég fájdalmas megoldásnak tűnik amíg nincs értelmes plugin rendszer.
Rájöttem hogy marhaságot beszélek, az API doksi úgy néz ki mintha lehetne legalább socketen keresztül beszélgetni vele. Valamiért úgy volt meg, hogy a Podman daemonless. Légyszi nyiss egy feature requestet Githubon a leírással és ha kap 1-2 upvote-ot átküzdöm magam rajta.
- A hozzászóláshoz be kell jelentkezni
A Dockert is lehet rootless módon indítani.
A magyar ember jelképe a hátrafelé nyilazás. Vakon rohanunk a semmibe, miközben a múltunkat támadjuk.
- A hozzászóláshoz be kell jelentkezni
Na közben picit részletesebben elolvastam a Podman doksit.
Egyrészt ez akasztott meg:
It is to be considered only as experimental as this point.
Másrészt pedig úgy tűnik, hogy ahhoz hogy az API elérhető legyen sajnos kötelezően futnia kell a Podman service-nek, azaz semmit nem nyersz vele a Dockerrel szemben. A konténer kezelést magát pedig nem szívesen gyógyítanám bele az SSH szerverbe hacsak nincs valami nyomós indok rá.
- A hozzászóláshoz be kell jelentkezni
containerd?
- A hozzászóláshoz be kell jelentkezni
Megoldhatónak tűnik első ránézésre. Használnád is?
- A hozzászóláshoz be kell jelentkezni
Problémamentesen használjuk PROD környezetben, igaz csak néhány száz konténerrel.
- A hozzászóláshoz be kell jelentkezni
Ja, nem az, hanem hogy az SSH szervert használnád-e. A containerd használhatóságával kapcsolatban nincsenek aggályaim.
- A hozzászóláshoz be kell jelentkezni
Kijött az új Podman és van benne Docker-kompatibilis REST API. Megnéztem az API leírást és mindent támogat ami kell a ContainerSSH-hoz, így ezzel is tudod használni.
- A hozzászóláshoz be kell jelentkezni
Ha jól értem, az a lényege, hogy egy ssh szerveren keresztül lövöd be a konténereket másik szerveren?
Ha igen, akkor nem lenne elég simán a context-et használni?
- A hozzászóláshoz be kell jelentkezni
Igen, ez a lényege, plusz csinál egy "attach"-et a konténerre és annak a ki/bemenetét összeköti az SSH-val.
Context alatt mit értünk itt?
- A hozzászóláshoz be kell jelentkezni
és erre még nem volt out-of-the-box megoldás?
Mert az ötlet egyébként baromi jó :)
- A hozzászóláshoz be kell jelentkezni
Én nem találtam.
- A hozzászóláshoz be kell jelentkezni
csak fogalom nelkul pofazok, de systemd-fele tcp socket altal inditott service altal inditott container megoldas nem mukodhet? mondom, nem tudom a konrketumokat, de systemd van eleg nagy rak ahhoz, hogy ilyent IS tudjon mar.
- A hozzászóláshoz be kell jelentkezni
Én sem vagyok Systemd szakértő, de ha jól értettem az úgy működne, hogy jön egy kapcsolat a 22-es portra, mire ő indít egy konténert amiben benne fut az SSH szerver ami fogadja a kapcsolatot. Azt nem oldja meg, hogy usertől függően pl. más könyvtárakat mountoljon. Azt persze megteheted, hogy rendszer szinten confolod a usereket és bekorlátozod arra hogy csak docker run-t vagy kubectl run-t futtathat, de őszintén, mennyi az esélyed úgy beconfolni hogy ne legyen benne kibúvó? Akkor már inkább megbízom a Go SSH libjében.
- A hozzászóláshoz be kell jelentkezni
Most gyorsan összeraktam egy authorized_keys command-os megoldást, és valami működést azért sikerült belőle kicsiholnom
szóval ssh-keygen után egy új user .ssh/authorized_keys-ébe:
command="docker run -it --rm ubuntu:18.04",no-port-forwarding,no-X11-forwarding,no-agent-forwarding ssh-rsa <ssh kulcs>
Még annó gitolite-nál láttam ezt így használva, sok ssh kulccsal is működik (ezért kell git clone-nál a git user-rel "belépni"), aztán lehet scriptelni, hogy ki milyen command-ot futat.
Nem tudom ez mennyire biztonságos, és mik a hátülűtői, aki jobban ért hozzá megmondaná, hogy ez miben tud kevesebbet?
(Közben megtaláltam a commentet lentebb, azért itt hagyom, hátha valaki nem ismerte)
- A hozzászóláshoz be kell jelentkezni
Én nem ismertem, köszi!
A magyar ember jelképe a hátrafelé nyilazás. Vakon rohanunk a semmibe, miközben a múltunkat támadjuk.
- A hozzászóláshoz be kell jelentkezni
Igen, ez lenne az alternatíva. Sajnos én sem tudom, hogy ez mennyire biztonságos, de az biztos, hogy meg kell oldanod a user managementet, illetve a Docker paraméterezését. ContainerSSH-val ez egy pár soros HTTP szerver.
Edit: még be kellene illesztened azt, hogy $SSH_ORIGINAL_COMMAND. Ott viszont izgalmas kérdés lesz, hogy nem lehet-e kijátszani és a Dockernek plusz paramétereket átadni.
- A hozzászóláshoz be kell jelentkezni
és mik a hátülűtői
Pl. ki és hogyan fogja feltakarítani a leszakadó kapcsolatok után bentragadt konténereket? (ez amúgy Jani kódjánál is megoldandó feladat, csak az ő kódjával ellentétben itt nem nagyon látom a triviális megoldás lehetőségét, amihez nem kell pl. az sshd-be mélyen beletúrni).
A másik, hogy így a gw gépre a usereknek identitást kell adni, míg ez elkerülhető a Jani verziójában - ez nagy könnyebbség, ha pl. MSSP-t akarsz játszani, és tenantonként mindenkinek saját user adatbázis lehetőséget kell adnod (= otthon, a saját kis LDAP-jában/AD-jában szeretné a saját usereit menedzselni).
- A hozzászóláshoz be kell jelentkezni
A leszakadó kapcsolatok utáni eltakarítás már megoldott, a ContainerSSH lerohadása után hátramaradó konténerek jelentenek még problémát.
- A hozzászóláshoz be kell jelentkezni
Szerintem valami sqlite-ba logolod oket container id-vel, az elmeletileg egyedi a hoston.
- A hozzászóláshoz be kell jelentkezni
Ok, és mizu a redundanciával? Illetve akkor letárolom az összes látott Docker / Kubernetes backend hozzáférési adatait? Sajnos nem ennyire egyszerű.
- A hozzászóláshoz be kell jelentkezni
Nem akarsz ilyen stateful szarságot.
Inkább rakni a konténerekre/podokra cimkéket, és vagy a létrehozó processzt újraindítani, és újraindítás után a cimkék alapján ismerje fel a korábbi futásának "ereményeit", vagy valami tőle független nagyon egyszerű takarítót futtatni (esetleg per Docker host / K8s cluster), ami valami heartbeatszerű jelzés hiánya esetén takarít. A K8s esetén a heartbeat lehet egy rendszeresen frissített státuszmező, az kb. semmibe nem kerül. A Docker nem tudom, hogy tud-e bármi hasonlót...
- A hozzászóláshoz be kell jelentkezni
A magyar ember jelképe a hátrafelé nyilazás. Vakon rohanunk a semmibe, miközben a múltunkat támadjuk.
- A hozzászóláshoz be kell jelentkezni
Nem. Ez csak arra jó, hogy a Docker újraindítson saját magán egy megállt komponenst.
Mi azt szeretnénk, hogy ha bármi okból a konténereket indító és vezérlő komponens abba a helyzetbe kerül, hogy nem tudja vezérelni a konténereket, akkor helyette valaki más takarítson. Mivel ők vagy ugyanazon a gépen futnak, vagy nem, így az is hibalehetőség, hogy mindenki működik, csak éppen a hálózat nem. Emiatt az nem segít senkin, ha ilyenkor újraindítom akármelyik komponenst, az segít, ha a konténer futtató környezeten belül van ez a takarító processz, mert nála csak azzal a hibával kell számolni, hogy rosszul írtam meg, és leáll/végtelen ciklusba kerül.
- A hozzászóláshoz be kell jelentkezni
Sima dockerben is lehet csinálni random labeleket, aztan a docker socketen keresztül futtatni valamit morickat ami takarit, ez gondolom lehet az is, amit janosszen irt (még nem neztem,, de todo).
- A hozzászóláshoz be kell jelentkezni
Valóban, de a ContainerSSHnál az a problematika, hogy a backendeket teljesen dinamikusan tudod konfigurálni. Vagyis a ContainerSSH nem tudja hogy milyen Kubernetes vagy Docker backendjeid vannak, csak a kapcsolat létrejöttekor eszmél rá. Erre valamilyen fájdalommentes megoldást kell találni.
- A hozzászóláshoz be kell jelentkezni
De ez önmagában miért baj? Gondolom a végén csak belebeszélsz a docker socketbe (legalábbis az example composeod beteszi volumeként). Ha van egy containerssh instance specifikus prefixed, akkor azzal tudsz labelezni, és egyrészt induláskor ki tudod takarítani a fenébe az előző futás után maradt szemetet, másrészt egyébként is tudod használni pl az event apit, ami egyébként az rm problémára is megoldást adhat, mert az event streamen visszajön a konténer exit codeja, nem feltétlen kell neked direkt superviseolni, ahogy gondolom teszed. pl:
2020-06-22T08:27:35.643104953+02:00 container die 0d1fd546b19d91a11ee81f4c611c5eb885352816d05e754a1971ae7d7fb00cc9 (exitCode=0, image=randomimage:latest, name=dazzling_dijkstra)
- A hozzászóláshoz be kell jelentkezni
A probléma abban rejlik hogy induláskor a ContainerSSH-nak nem feltétlenül vannak meg a hozzáférési adatok a backendhez mivel azokat a config szerver is visszaadhatja usertől függően. Tehát pl. tudsz olyat csinálni hogy minden usert a saját Docker hostjára vagy Kubernetes clusterére küldesz be és ezeket csak a config szerver ismeri (amit Te írsz), a ContainerSSH nem.
Az rm egy érdekes ötlet de sajnos csak a Docker backenddel működne. A Kubernetes API nem támogatja a podok törlését futás után.
- A hozzászóláshoz be kell jelentkezni
Na jó, valamikor igyekszem elolvasni, hogy pontosan hogy is működik, aztán jövök ötletelni :) (Mert azzal elsőre mélyen egyetértek, hogy nem kéne valami single point of state adatbázis, de látom, hogy van itt azért architektúra, amit fel kéne fogni)
- A hozzászóláshoz be kell jelentkezni
Olvasd el a readme-t, az elmagyarázza az alapötletet. :)
- A hozzászóláshoz be kell jelentkezni
Ezt terveztem :-)
- A hozzászóláshoz be kell jelentkezni
Na, megnézegettem. Mikor csak átfutottam, akkor még féltem tőle, hogy kódot is kell túrni, mert a hogyan indulunk környékén lesz valami varázslat, de a readmet olvasva sajnos az van, hogy annyira frankó dinamikus architektúrát rajzoltál, hogy azzal kissé lábon is lőtted magad.
Mivel még a backendek listája sem ismert, ezért esélyed sincs saját hatáskörben stateless megoldani a dolgot. Kb a következő lehetőségeid vannak, ahogy én látom:
- beismered, hogy nincs esélyed, és egyszerűen a backendre hagyod a takarítást, maximum valami konfigurálható labelezést vagy ilyesmit csinálsz, hogy segítsd a túloldalt megtalálni mi nem kell már. Ez szép tiszta, csak hááát...
- Megpróbálhatsz magad minden backend példányra letenni valami autonóm cleanup mechanizmust magad, akár per backend akár per container. Ez utóbbi talán kicsit egyszerűbb mondjuk sidecar vagy valami, de az egész bűzlik a 22es csapdájától (ki takarítja a takarítókat), meg egyébként is antipattern szaga van egy ilyen környezetben
- Poor man's cron jelleggel mikor egyébként is mész a backendre, akkor takarítasz. Ez olyan poor man's, meg a sohatöbbet nem használt backendeken még szemetet is hagy.
- beismered, hogy nem fog menni memória nélkül, és választasz az sqlitenál valami testhezállóbbat. Mondjuk egy etcd-t vagy ilyesmi, amit a user úgy skáláz elosztottan, ahogy akar. Aztán a containerssh abba szépen teszi el, hogy mit hol indított, aztán ha egyszerűre akarod venni, akkor néha takarít az, ha meg szépre, akkor csinálsz egy takarító microservicet
- esetleg ezt még tovább lehet szépezni, és etcd helyett mondjuk egy consult használni, és serviceként regisztrálni a containereket, még valami healthchecket is kitalálni rájuk. Így minimum egy tiszta APIt kapsz a takarító service alá, ha szerencséd van akkor a consul watchokkal lehet, hogy fel is lehet takarítani, ha a healthcheck azt mondja, hogy már nem fut.
Illetve ha te takarítasz, akkor az tulajdonképp lehet opcionális, ha valakinek nem kell, akkor goto 1.
- A hozzászóláshoz be kell jelentkezni
Én inkább arra gondoltam, hogy bevezetek plusz egy endpointot a config szerveren ami visszaad egy backend-listát takarítás céljából induláskor. Illetve természetesen ugyanezt a konfigurációban is megadhatod. Ha nem adsz meg semmit akkor nem takarít.
- A hozzászóláshoz be kell jelentkezni
Persze, lehet tenni ezt a config szerverbe is, de tartani neki is kell valahol, bár abban igazad van, hogy ő jó eséllyel egyébként is rendelkezik ezzel az infóval :)
- A hozzászóláshoz be kell jelentkezni
ilyenkor a futo docker nem kerul stop allapotba? egyszeruen csak torolni kell a stoppedeket. nyilvan valahogy tarolni hogy melyik tartozik ehhez. pl nevben valami prefix.
A vegtelen ciklus is vegeter egyszer, csak kelloen eros hardver kell hozza!
- A hozzászóláshoz be kell jelentkezni
Igazából lehet, hogy egy --rm a docker runnak pont elég
- A hozzászóláshoz be kell jelentkezni
A ContainerSSH nem használja a --rm flaget mert akkor nem tudja lekérdezni a konténer exit kódját és visszaküldeni az SSH csatornán keresztül.
- A hozzászóláshoz be kell jelentkezni
Igazából csak dockerből indultam ki, ott van egy úgynevezett context amivel be tudsz állítani egy szerver elérést egy azonosítóval (ssh, kulcsot pedig .ssh/config).
Utána ki tudsz adn bármilyen parancsot amit egy adott szerveren fog futtatni a docker.
pl.:
#A valami-szerver alatt futó docker konténereket listázza
docker --context valami-szerver ps
#Ez pedig a valami-masik szerveren
docker --context valami-masik ps
Nagy hiányosság volt, hogy docker-compose alatt ez nem működött, csak dev verziókban volt benne, az is bugos volt tapasztalataim szerint.
Legutóbb már úgy láttam, hogy stable verzióban is bekerült.
- A hozzászóláshoz be kell jelentkezni
Ja értem. (Itt hangsúlyosan nem arról van szó hogy nekem kell containerekbe SSH-znom, hanem arról, hogy nagy számú usernek akarsz SSH szolgáltatást nyújtani.)
Persze, meg tudod csinálni, hogy minden usernek van egy context-je és az OpenSSH-t rákényszeríted hogy minden usernek fixen a "docker" parancsokat hajtsa végre (force-command ha jól emlékszem). Nekem ezzel az a bajom, hogy 1. minden usernek léteznie kell a gazdagépen 2. a konténeren kívül kerül végrehajtásra egy külső parancs, tehát ha abban van bármivéle escape baki, el van csettintve az OpenSSH config ezer tekerentyűje közül egy, stb. akkor a user a konténeren kívül köt ki és mindent lát.
Arról lehet vitatkozni, hogy az OpenSSH elconfolása-e a nagyobb veszély vagy a Go SSH libje, de nekem személy szerint az OpenSSH-s megoldás eléggé bántja a szememet.
- A hozzászóláshoz be kell jelentkezni
Köszi a választ. Lényegében a hoszting szoftvert akartad akkor megoldani, értem. Így valóban biztonságosabb mint a context.
- A hozzászóláshoz be kell jelentkezni
Szuper! Ügyes vagy, köszönjük! Én már nyomkodom.
- A hozzászóláshoz be kell jelentkezni
De ez nem is javaban van irva, mi tortent?!?! :P
- A hozzászóláshoz be kell jelentkezni
Efpe barátom, látom nem olvastad el a cikket. :D (Lebuktál.) A Javas verziót megírtam 2017-ben de sajnos az SSH library (Apache Mina) és a Docker library nem egészen működött együtt úgy ahogyan kellene.
- A hozzászóláshoz be kell jelentkezni
mi a meglepo? sosem olvasok el semmit, csak esz nelkul kommentelek :'(
- A hozzászóláshoz be kell jelentkezni
Ikszdé
- A hozzászóláshoz be kell jelentkezni
Amikor Javas SSH megoldást kerestem, a Mina nem jött szembe. Köszi, így van nég egy kód, amiből kiindulhatok. Javas kód lesz, ha egyszer elkészült.
- A hozzászóláshoz be kell jelentkezni
Ha érdekel, megosztom a kódot ami nálam a lemezen van, de nem “alkalmas a publikációra”. Arra figyelj, hogy a Mina default cipher setje már nem aktuális, tekergetni kell rajta.
- A hozzászóláshoz be kell jelentkezni
OpenSSH kód alapján kezdtem nulláról, merrt nem találtam olyat, ami csak az encryptiont kezeli, és a többit vagyis a plain text csomagokat már szabadon kezelhetem. A titkosítást megírni meg elég bonyolult. Host key, sokféle algo. Én kitettem a kódomat githubra, de még semmire sem jó.
Köszi, bármi segítséget szívesen fogadok. Az nagyon hasznos, ha látom, hogyan kell használni ezt a libet.
- A hozzászóláshoz be kell jelentkezni
Irj rám privátban, adok egy kicsontozott változatot abból az SSHD-ból amit anno írtam. (Megszereztem rá a jogokat de nem éppen szép a kódja.)
- A hozzászóláshoz be kell jelentkezni
subscribe
- A hozzászóláshoz be kell jelentkezni
A kollégák találtak benne egy bugot, ha használjátok frissítsetek 0.2.0-ra. Ezen felül kapott egy weboldalt és az auth-config szerver egy normális API dokumentációt.
- A hozzászóláshoz be kell jelentkezni
Időközben megjelent a 0.3.0 szép új Prometheus metrikákkal. Kollégák, ismerősök jelentik, hogy a 0.2.2-t Augusztus eleje óta használják és stabilan működik.
- A hozzászóláshoz be kell jelentkezni