Scriptul auth-user-pass-verify al OpenVPN: codul de ieșire corect
Starea de ieșire a hook-ului este decizia, nu linia sa de log. Asociază rezultatele verificatorului cu 0, 1 sau amânat, citește fișierul de acreditări ca date și eșuează închis.
OpenVPN acționează pe baza exact a unei ieșiri a unui script de autentificare: starea de ieșire. Orice altceva face scriptul este decor. Un hook poate ajunge la verificatorul corect, analiza răspunsul și afișa o linie prietenoasă, dar poate returna o stare care înseamnă opusul intenției autorului. Citește mai întâi contractul și scrie adaptorul în jurul lui, iar toată această clasă de erori dispare.
Contractul este mic: identifică contul trimis, pune verificatorului aprobat întrebarea dorită și acceptă doar rezultatul pozitiv documentat al acelui verificator pentru acea cerere. Tot restul este infrastructură.
Cele trei stări pe care hook-ul le poate returna
Pentru auth-user-pass-verify, manualul OpenVPN 2.6 definește codul de ieșire 0 ca acceptare, 1 ca respingere și 2 ca autentificare amânată. Acestea sunt singurele trei răspunsuri pe care le înțelege serverul, iar fiecare are o consecință diferită pentru conexiune. Un script care iese cu starea ultimei sale comenzi a lăsat, de fapt, un apel de log sau un pas de curățare să voteze. Scrie starea explicit în fiecare ramură, inclusiv în ramurile care nu au ajuns niciodată la verificator.
Succesul HTTP și succesul autentificării sunt straturi separate, iar confundarea lor este cea mai frecventă cauză de eșec a acestui hook. Un răspuns 202 înseamnă că cererea a fost acceptată pentru procesare, nu că o parolă a fost verificată. Definește starea așteptată, forma răspunsului și verdictul final din contractul API care ți-a fost dat, și nu inventa un nume de câmp pentru că pare plauzibil.
Dacă răspunsul ajunge într-adevăr mai târziu, aceea este calea amânată și trebuie construită ca atare. O încercare amânată care nu se finalizează niciodată ține resurse până la expirarea timpului limită.
Citește fișierul de acreditări exact așa cum este scris
În metoda documentată prin fișier, serverul scrie numele de utilizator și parola ca primele două linii ale unui fișier temporar, transmite acea cale scriptului și elimină fișierul când scriptul revine. Citește cele două linii ca date: nu rula niciodată fișierul prin source, nu îl evalua niciodată și nu lipi niciodată conținutul lui într-o linie de comandă unde tabelul de procese îl poate vedea. Păstrează parola octet cu octet, pentru că normalizarea, așa cum ai normaliza un nume de utilizator, schimbă acreditarea în tăcere. Directorul pentru acel fișier temporar este o decizie de implementare, așa că verifică dacă există și dacă nu este lizibil de către toată lumea de pe gazdă.
Ține acreditarea verificatorului separat de cea a utilizatorului: aparține integrării cu gateway-ul, trăiește în depozitul de secrete al platformei și are nevoie doar de permisiunea de a verifica, deci nu este dovada că o anumită persoană s-a autentificat. Nu lăsa nici hook-ul să devină un al doilea verificator de parole. Reimplementarea manuală a comparației de hash nu devine sigură prin optimizarea buclei, iar un verificator întreținut înțelege deja schema sărată și costisitoare a depozitului de conturi.
Decide ce înseamnă un răspuns neclasificabil
Expirările de timp, erorile de transport, răspunsurile malformate și un backend indisponibil împărtășesc o proprietate: niciunul nu este o verificare pozitivă. Hook-ul ar trebui să eșueze închis pentru fiecare dintre ele și să înregistreze un motiv pe baza căruia un operator să poată acționa. Acel motiv aparține unui log protejat, nu unui mesaj returnat persoanei care încearcă să se conecteze.
Fii la fel de atent cu căile care nu ajung deloc la verificator. O valoare de configurare lipsă, un secret ilizibil sau o dependență neinstalată ar trebui să producă o respingere cu un marker operațional distinct în loc de o acceptare accidentală. Testează acele ramuri eliminând dependența într-un laborator, în loc să raționezi despre ele. Acolo unde o eroare de logare poate schimba starea de ieșire, logarea a devenit parte din decizie și trebuie făcută inofensivă.
Configurația serverului contează și aici: scripturile definite de utilizator sunt respectate doar când configurația în execuție le permite la nivelul de securitate cerut, iar acea setare este o alegere deliberată, nu o valoare implicită de ridicat.
Verifică verdictul, nu linia tipărită
Construiește un test care inspectează direct starea de ieșire. Scrie un fișier de acreditări eșantion, rulează hook-ul pe el cu un cont știut bun și unul știut rău, și citește starea raportată de shell, nu textul tipărit de script. Acea singură verificare prinde majoritatea erorilor de contract înainte ca un client să se conecteze.
Apoi treci aceleași cazuri printr-un client real împotriva unui ascultător non-producție și confirmă ce a înregistrat serverul: acceptat, respins sau amânat. Acoperă un cont dezactivat, o parolă greșită, un răspuns malformat al verificatorului, o expirare de timp și un verificator inaccesibil. Dacă vreun caz ajunge într-o stare pe care nu o poți numi, adaptorul nu este terminat.
Păstrează corespondența dintre rezultatul verificatorului și starea de ieșire lângă script în depozit, ca următorul inginer să poată citi contractul fără inginerie inversă a codului.