RADIUS aan OpenVPN koppelen: plugin of scripthook?
De oude RADIUS-plugin is gebonden aan de serverbuild waarvoor hij is gecompileerd. De auth-user-pass-verify-hook vervangt hem, maar verplaatst het vertrouwen naar jouw script.
De plugin wordt nog steeds aangeraden in threads die ouder zijn dan de huidige builds, en op een gisteren gecompileerde server faalt hij bij het laden. Dat is geen configuratiefout die je met een pad oplost. De plugin en de scripthook lossen hetzelfde probleem op verschillende lagen op, en overstappen van de een naar de ander verandert wat er geïnstalleerd moet worden, wat met serverrechten draait en wat een mislukte login je werkelijk vertelt.
De mythe: de plugin is het ondersteunde pad
Een plugin is een gedeeld object dat in het OpenVPN-proces wordt geladen, dus het moet passen bij de interface die dat proces blootlegt. Builds veranderen, verpakking verandert, en een bibliotheek die voor een oudere interface is gecompileerd weigert simpelweg te laden. Niets in de serverconfiguratie kan die kloof overbruggen, daarom eindigt het advies "installeer gewoon radiusplugin" met een server die niet start.
De scripthook staat juist buiten het proces. OpenVPN voert een programma uit, geeft het de inloggegevens en leest een oordeel terug. Die ontkoppeling laat hem upgrades overleven, en maakt hem ook jouw verantwoordelijkheid op een manier waarop de plugin dat nooit was.
Geen van beide benaderingen is veiliger door zijn constructie. De ene draait vreemde code in de daemon; de andere draait jouw code ernaast met de inloggegevens in de hand. De juiste vraag is welk van die twee risico's je werkelijk kunt beheren.
Wat de plugin samenbond
De plugin had zijn eigen configuratiebestand met de RADIUS-host, het gedeelde geheim, het aantal herhaalpogingen en de time-out, en de serverconfiguratie verwees er met één regel naar. De omgang met inloggegevens bleef in het serverproces, wat betekende dat het wachtwoord nooit een procesgrens overstak die de beheerder moest beveiligen.
De prijs was koppeling. Elke OpenVPN-upgrade riskeerde een incompatibele interface, en elke distributie die het pakket opnieuw bouwde riskeerde een bibliotheek die niet meer paste. Als dat gebeurt, is de fout luid en onmiddellijk, en dat is de enige genade van het ontwerp.
Als zo'n plugin nog op je build laadt, kan het de kleinere operationele oppervlakte zijn. Bevestig de interface waarvoor hij is gebouwd, houd hem vastgepind op de build die je hebt getest, en behandel elke upgrade als een wijziging die een volledige logintest vereist, niet als een routineuze pakketupdate.
Waarop de scripthook werkelijk vertrouwt
De hook wordt geconfigureerd met auth-user-pass-verify en een leveringsmechanisme: omgevingsvariabelen of een tijdelijk bestand. In de omgevingsvorm vereist OpenVPN script-security 3, het gedocumenteerde niveau dat blootstelling van het wachtwoord aan scripts toestaat. Dat niveau is een bewuste verzwakking van de standaard, en het moet worden behandeld als een toestemming met een onderbouwing erbij.
Alles wat het script aanraakt erft dat vertrouwen. Het moet eigendom zijn van root, niet schrijfbaar voor groep of anderen, met een absoluut pad worden aangewezen, en vrij zijn van elke plek waar een niet-vertrouwde waarde een shell bereikt. Zet elke variabele tussen aanhalingstekens, weiger onverwachte tekens, en bouw nooit een commando uit de opgegeven gebruikersnaam. Een script dat bij elke loginpoging als root draait, verdient één keer een beoordeling precies op die vier eigenschappen.
ls -l /usr/local/sbin/radius-auth.sh
stat -c '%U %a' /usr/local/sbin/radius-auth.sh
De bestandsleveringsvorm vermijdt het probleem van omgevingserving en geeft de inloggegevens aan het script via een tijdelijk bestand met beperkte rechten. Als je client dat ondersteunt, is het meestal de betere standaard, hoewel het één object meer toevoegt om bij een fout op te ruimen.
Exitcodes bepalen of je open faalt
De exitstatus van het script is het oordeel: nul accepteert, niet-nul weigert. Het patroon dat problemen veroorzaakt is een shellscript dat alleen accepteert wanneer het RADIUS-antwoord een bepaald acceptatietoken bevat en voor al het andere een fout teruggeeft, omdat het daarmee drie verschillende gebeurtenissen in één antwoord samensmelt. Een verkeerd wachtwoord, een onbereikbare server en een misvormd antwoord worden allemaal dezelfde weigering.
Scheid die gevallen in het script, ook als de hook alleen accept of weiger kan teruggeven. Log de backend-uitkomst apart, alarmeer bij time-outs en transportfouten, en maak in monitoring duidelijk wanneer authenticatie faalt omdat de dienst plat ligt en niet omdat gebruikers zich vertypen.
Twee gewoonten houden de rest verstandig. Als RADIUS de autoriteit is, moet het de enige plek zijn waar een wachtwoord wordt gecontroleerd, want een schaduwtabel maakt twee antwoorden op dezelfde vraag en het tweede is een aanvalsoppervlak waar niemand naar kijkt. En onthoud dat de hook bij elke nieuwe poging opnieuw wordt aangeroepen, dus een traag script met een ongeduldige client wordt een versterker voor het raden van wachtwoorden, tenzij je een vertraging of een beleid aan de RADIUS-kant toevoegt.
Wat je opgeeft als het certificaat verdwijnt
Veel implementaties van deze vorm schakelen de controle van het clientcertificaat volledig uit, en laten een gebruikersnaam en een wachtwoord als de hele claim van de client. Wat met die instelling verdwijnt, is identiteit op basis van certificaat. Het kanaal blijft versleuteld, maar het enige dat de client noemt is het RADIUS-oordeel. Alles stroomafwaarts dat vroeger op een certificaatonderwerp leunde, moet nu op de gebruikersnaam leunen.
Houd de bescherming van het besturingskanaal in stand zodat een niet-geauthenticeerde peer de handdruk niet kan onderzoeken of overspoelen, en gebruik username-as-common-name wanneer de configuratie per gebruiker van de common name afhangt. Beheerde gateways lossen dit vaak anders op, door certificaatauthenticatie te beëindigen bij een gateway die EAP-TLS met RADIUS spreekt, en in dat geval geldt geen van deze serverrichtlijnen. Kopieer het model dat je eigen platform documenteert, niet dat van een naburig product. De richtlijnen die ertoe doen verschillen genoeg dat het mengen ervan een configuratie oplevert die parseert en daarna niemand authenticeert.