Dev napló: SSH bejelentkezés OAuth2-vel

Gondolatok a ContainerSSH fejlésztése közben.

Hagyományosan SSH szerverre jelszóval vagy SSH kulccsal jelentkezünk be. Ezen felül van még néhány kevésbé ismert megoldás is, mint például a keyboard-interactive, amelyet sokszor kétfaktoros azonosításhoz használunk, vagy pedig a GSSAPI, ami lehetővé teszi a Kerberos autentikációt (vagyis pl. a Windowsos azonosítással való bejelentkezést.) Egy azonban hiányzik a listából: a single sign-on.

OAuth2: Miért?

Amikor Tatu Ylönen 1995-ben feltalálta az SSH-t a legtöbb terminál 80x25 karakter méretű volt és a Netscape Navigator egy éves születésnapját ünnepelte. A webes single sign-on rendszerek még a láthatáron sem voltak. Az SSH protokoll természetesen fejlődött az évek alatt, de a legfrissebb RFC is van vagy 10 éves.

Hagyományosan a nagyobb cégek (pl. telkok) a tűzfalaikra és az azok által izolált hálózati szegmensekre támaszkodtak az SSH hozzáférés bekorlátozására az Internet felől. Néhány helyen ugyan implementáltak központi azonosítást pl. LDAP segítségével vagy konfiguráció-menedszmenttel, de ez inkább a kivétel mintsem szabály. A legtöbb helyen csak akkor került implementálásra, ha valamilyen külső szabály (pl. PCI-DSS) megkövetelte.

Az elmúlt években azonban már a nagyobb cégek is kimozdultak a saját, jól ellenőrzött hálózati környezetükből és lépéseket tettek a felhők felé, amivel együtt a hozzáférés-korlátozás nagyobb kihívást kezdett jelenteni. Maga a hozzáférés-kezelés természetesen nem újkeletű probléma, így pl. a SAML mint SSO megoldás is több, mint 15 éves múltra tekint vissza. A születési korának megfelelően persze a SAML egy XML szörnyetek, amit ember legyen a talpán aki hiba nélkül implementál.

Az utóbbi időben az OpenID Connect (OIDC), mint az OAuth2 kiterjesztése, egyre nagyobb teret nyert. (Ez nem összekeverendő az OpenID-val, a kettő teljesen más.) Mára már a Microsoft Active Directory Federation Services is támogatja a SAML 2.0 mellett, és akár a Kuberneteshez is használhatjuk felhasználói azonosításra.

Egy dolog azonban fájóan hiányzik: az SSH. Az a protokoll, amivel a Kubernetes alatti, vagy éppen "hagyományos" szolgáltatásainkat futtató szerverekhez hozzáférünk.

A GSSAPI természetesen megoldást jelenthet, ha a gépünk egy Windows Domain tagja, de a Bring Your Own Device korában ez talán egy picit túlhaladott.

OAuth2: Hogyan?

OK, szóval már nem 1995-öt írunk, hogyan vesszük rá az SSH-t, hogy böngészőn keresztül autentikáljon?

A dolog nyitja a keyboard-interactive autentikáció, ami az RFC 4256-ban került szabványosításra. Ezt az azonosítási megoldást szinte minden SSH kliens támogatja és lehetővé teszi, hogy az SSH szerver egy kérdés-listát küldjön a kliensnek, amit a felhasználónak meg kell válaszolnia. Ezen felül a szerver küldhet egy utasítás-szöveget is, amelyet arra tudunk felhasználni (abuzálni), hogy megjelenítsük a felhasználónak az OAuth2 azonosítás linkjét.

Innentől viszonylag egyszerű a játék: az első opció az un. authorization code flow, amelyben a felhasználó bejelentkezik a böngészőjében, majd egy kódot vissza kell másolnia az SSH konzolba. A kód alapján a szerver ezek után lekérdezi a felhasználó adatait. A demóért lásd ezt a 17 másodperces videót.

A mások megoldás a device code flow, ahol a usernek a link mellett egy kódot jelenítünk meg, amelyet a linkre kattintva meg kell adnia. Itt a kliensnek az utasítás-szöveg mellé nem mellékelünk kérdéseket, hanem a szerver a visszaigazoló üzenet után elkezdi kérdezgetni az OAuth2 szervert, hogy a folyamat véget ért-e már, majd amint vége, a felhasználói adatok lekérdezése után beengedi a felhasználót. A demót ebben a 25 másodperces videóban láthatod.

Az utóbbi felkínálná magát egy QR kód megjelenítésére is, ezt azonban az OpenSSH nem támogatja, mivel elvágja az utasítás szövegét 255 karakter után és az US-ASCII-n kívül más karaktereket nem is engedélyez.

Kliens támogatás

Jelen post írásakor a következőket tapasztaltuk:

  • Az OpenSSH korlátozza az utasítás mező hosszát 255 karakterre és nem támogatja az UTF-8 karaktereket.
  • A PuTTY megmutatja a linket, de azt 78 karakter után eltöri. Ezt jeleztük a fejlesztőknek, de visszajelzést még nem kaptunk.
  • A WinSCP megjeleníti az utasítás-szöveget, de az nem kattintható vagy másolható. A szoftver fejlesztője épített egy demo buildet ahol ezt javította, de ez még nem ment ki élesbe. (Ha a link kellően rövid, akkor ez nem jelent problémát.)
  • A Filezilla a PuTTY-hoz hasonlóan eltöri a link szöveget 78 karakter után, valamint duplázza az & karaktert. Ezt a nightly buildben javították. Ezen felül nem jeleníti meg a device flow-ban a kérdések nélkül küldött instrukciós szöveget.
  • A Termius nem jeleníti meg az utasítás szövegét a mobil verzióban, valamint nem jelölhető vagy kattintható a szöveg a desktop verzióban. Ezt jeleztük nekik és továbbították a fejlesztőknek.
  • A Bitvise nem teszi kijelölhetővé vagy kattinthatóvá a linket. Ezt jeleztük és bugként kezelik.
  • A JuiceSSH egyáltalán nem jeleníti meg az instrukciós szöveget Androidon. Ezt jeleztük, de visszajelzést nem kaptunk.

Mikor?

Hamarosan. A ContainerSSH-ban már működik egy igen-igen házitákolt verzió, de ezt még csiszolni kell. Mivel felderítetlen vizeken evezünk a release dátum bizonytalan, és szeretnénk megvárni amíg legalább néhány közkedvelt SSH kliens teljeskörűen támogatja ezt a funkcionalitást.

Ezúton is köszönetet szeretnénk mondani mindazoknak, akik ötletekkel, javaslatokkal és teszteléssel támogatják a projektet. Ez a blog post az angol nyelvű ContainerSSH post magyar fordítása.

Hozzászólások

QR kodra alternativa: https://zxing.org/w/chart?cht=qr&chs=350x350&chld=L&choe=UTF-8&chl=http…

SSH kliens amit meg erdemes lenne tesztelnetek: MobaXterm. Ez alapvetoen egy X szerverkent hirdeti magat, de valojaban egy nagyon okos, profilokat is kezelni tudo OpenSSH/SFTP kliens Windowsra (ami egyebkent mellesleg X szerver is).

Illetve a linkhossz problemara nem lehetne megoldas egy goo.gl -szeru linkrovidito hasznalat? 

Blog | @hron84

valahol egy üzemeltetőmaci most mérgesen toppant a lábával 

via @snq-

A linkelt QR kód link hogy oldja meg azt a problémát, hogy nem tudjuk a konzolba kirajzolni mert nincs elég karakter? QR kódot renderelni mi is tudunk, csak nincs mivel. :)

MobaXterm: a fedél alatt ránézésre OpenSSH-t használ.

Linkhossz: de, ez lesz a megoldás, csak nem publikus linkrövidítővel. Az picit security issue lenne. :)

OK, szóval már nem 1995-öt írunk, hogyan vesszük rá az SSH-t, hogy böngészőn keresztül autentikáljon?

Könnyen lehet, hogy nem értem kellő mélységben a problémát, de a fenti kérdésedet tippre valakik már megoldották, amikor mindenféle webes terminal-t faragtak a GUI-kra (pl freenas).

"The only valid measurement of code quality: WTFs/min"

A webes terminál is valahogyan authentikál, mert nem a login promptot kapod meg, hanem már a bejelentkezett állapotot. 

Erre gondoltam, hogy érdemes megnézni miként csinálja...

"The only valid measurement of code quality: WTFs/min"

Ha megnézed pl. a Teleport nevű SSH szervert, ők egy saját SSH klienst építettek, ami HTTP-n autentikál, majd egy rövid lejáratú átmeneti tokennel jelentkezik be az SSH sessionbe. Ezt nem szeretnénk, a cél az, hogy egy normál SSH klienssel be tudj jelentkezni.

Raadasul tobbfele webes terminal van, van amelyik szerver oldalon nyit egy pty-t, amibe behivja az aktualis paraszt login shelljet (egy getent-tel lekerdezi), es ennek a kimenetet kommunikalja a klienssel. Nem minden webes terminal epit SSH kapcsolatokat ki. Ugy konnyu authentikalni.

Itt tenyleg az a problema, hogy az SSH-t viszonylag nehez osszehozni kulso authentikacios forrasokkal, a legtobbszor a PAM-on keresztul huznak be dolgokat, de az az Oauth2 eseten nem jarhato ut. 

Blog | @hron84

valahol egy üzemeltetőmaci most mérgesen toppant a lábával 

via @snq-

...de az az Oauth2 eseten nem jarhato ut. 

Ez igy nem egeszen igaz, a PAM tud keyboard-interactive autentikaciot, igy az OAuth2 is jarhato ut valamennyire. Lasd pl ezt vagy ezt a projektet. Az mas kerdes, hogy ezek csak OIDC-t tamogatnak es ranezesre csak egyetlen use case-re keszultek, vagyis nem biztos, hogy egy prod kornyezetben hasznalnam,

A mások megoldás a device code flow, ahol a usernek a link mellett egy kódot jelenítünk meg, amelyet a linkre kattintva meg kell adnia.

Biztos én nem értek valamit, de ha a linket és a kódot is te generálod, akkor miért nem adod át a kódot a linkben, pl. egy query paraméter formájában? Nem látom mitől jobb, ha a kódot külön kell megadni.

A kódot a device flow esetén az OAuth2 szerver generálja amit az SSH szerver lekéri és kiadja a usernek. A usernek a kódot be kell adnia az OAuth2 szerver által adott oldalon. Azaz nem tudom átadni a kódot, hiszen pont az a lényege, hogy a usernek interakcióba kell lépnie a szerverrel.

De önmagában a link megnyitása és az ezzel járó authentikáció miért nem elég interakció? Ha a link egyedi, akkor már úgyis tudod, hogy melyik ssh sessiont indította az authentikált user, mert csak úgy nyithatta meg a linket.

Másként megfogalmazva, a link és a kód ugyanazon a csatornán érkezik (ssh session) és ugyanazon a csatornán keresztül is jut vissza a szerverhez (authentikált https session), vagyis szerintem a user feleslegesen van dolgoztatva a kóddal.

Ez nem egy olyan dolog, amit én tudok befolyásolni, ezt az OAuth2-ben szabványosították. Ha jól értettem az eredeti célt, itt az a vágy, hogy az autentikáció akkor is működjön, ha a bejelentkeztetni kívánt eszköz és a jóváhagyó eszköz között nincs közvetlen hálózati kapcsolat. Így például egy okos TV megjeleníthetné a relatíve rövid URL-t, amit a telefonodon begépelsz és ott beütöd a kódot, jóváhagyva a bejelentkezést.

Azt hiszem megvan mit ertettem félre, úgy gondoltam a kódot te generálod amivel azonosítod az ssh sessiont, illetve az authentikáció után is egy saját szolgáltatás fut, ami bekéri a kódot és átadja az adatokat az ssh szervernek. De ha jól értem itt az ssh szerver közvetlenül kommunikál az OAuth2 szerverrel, nem fut saját szolgáltatás https-en.

Igen, ez így van, az SSH szerver kommunikál az OAuth2 szerverrel, majd elküldi a usert azonosítani az OAuth2 szerverhez és a háttérben kérdezgeti a szervert, hogy készen van-e.

A normál Authorization Code Flow-hoz kell a visszatéréskor egy HTTP szerver, de kizárólag a visszatérő kód megjelenítéséhez.

Szerkesztve: 2021. 04. 21., sze – 18:04

Kár, hogy az ilyen szakmai, magyar (ld. Hungarian Unix Portal), kifejezetten érdekes, új technológiát és innovációt tartalmazó hírek nem érnek címlapot. Pedig ez mindannyiunk érdeke lenne... Helyette a politikai hőzöngésre és kókemény odamondogatásra van idő a főszerk részéről, meg totálisan offtopik szavazások kipakolgatása...

Ami a projektet illeti: Továbbra is csak azt tudom mondani, hogy nagyon tetszik, teljesen életszerű a problémafelvetés. Remélem meggazdagszol belőle, de legalább részlegvezető leszel majd a Red Hatnél :D

Pedig hát nem egy rocket science

  • cikként beküldeni
  • ha blog lett, egy levelet dobni, hogy emeljem ki

20 másiknak sikerült! ;)

(Mielőtt nekiállsz erőlködni... Ne tedd! Számtalan példa volt arra, hogy blogbejegyzést kiemeltem a főoldalra.)

trey @ gépház

Köszi, de ezt szándékosan nem küldtem be a nyitólapra. A releasekről szóló híreket beküldöm, de ez még kezdeti stádiumban van. Ha megjelenik a 0.5 ezzel a feature-el belinkelem ezt a postot is.

Ami a meggazdagodást illeti, nem szeretnék, mert annak sajnos velejárója a mai ismert open source üzleti modellek mellett, hogy valahol el kell vennem a projektből. A Red Hat managereimnek viszont tetszik a projekt. :)