De dienst start, leest het profiel zonder klachten en sterft dan op een regel die niets met de zaak te maken lijkt te hebben: hij kan ca.crt niet openen. Aan het certificaat is niets veranderd, en het profielpad in het unit-bestand is absoluut. Precies die combinatie is de aanwijzing. Het pad dat je opgaf, wijst één bestand aan, en de namen in dat bestand worden heel ergens anders opgelost, dus een start die volledig gekwalificeerd lijkt, kan zijn sleutels nog steeds uit een map lezen die niemand bedoelde.

De storing heeft weinig oorzaken, en het loont ze op volgorde te scheiden: de basismap die het proces werkelijk had, de startcontext van de dienst en de rechten of sandbox rond het bestand zodra het pad klopt. Elk laat een ander spoor achter — in de unit, in het proces en op het bestandssysteem.

Het profielpad is geen basismap

Stel je een proces voor dat in /tmp start en /etc/vpn/prod/tenant-a.ovpn krijgt. Binnen dat profiel noemt de regel ca ca.crt een relatief pad. Niets in het argument dat het profiel vond, herschrijft die naam, dus het proces zoekt /tmp/ca.crt en meldt een ontbrekend bestand.

Verwarrend is de volgorde van de fouten. OpenVPN parseert eerst de configuratie en opent genoemde bestanden zodra het ze tegenkomt, dus een typefout in het profiel wordt gemeld voordat een sleutel wordt aangeraakt, terwijl een ontbrekend certificaat pas verschijnt wanneer het parsen zo ver komt. Een profiel dat laadt, is dus bewijs dat de syntaxis klopt, niet dat de bestanden die het noemt, zijn gevonden.

Wat de handleiding scheidt: --config en --cd

De handleiding van OpenVPN 2.6 beschrijft twee verschillende opties. De ene laadt een configuratiebestand. De andere wisselt de map van het proces voordat configuratie, sleutel, script en andere bestanden worden gelezen, en vereist een absolute map zonder verwijzing naar de huidige.

openvpn --cd /etc/vpn/prod --config tenant-a.ovpn

Die aanroep is een vorm, geen opdracht om iemands anders profiel te starten. Wat hij oplevert, is determinisme: de basis voor elke relatieve naam in de keten staat in het commando in plaats van geërfd te worden van de shell of beheerder die het proces startte. Het alternatief is even geldig en voor een dienst vaak beter: laat de werkmap met rust en maak elk genoemd bestand absoluut binnen het profiel.

Wat je ook kiest, controleer de hele keten en niet de eerste fout. Een profiel kan een ander configuratiebestand binnenhalen, en de relatieve namen van het ingevoegde bestand worden opgelost tegen dezelfde procesmap, niet tegen de map van het bestand dat ze invoegde. Logpaden, authenticatiebestanden en hulpscripts volgen dezelfde regel.

De dienst start elders

Een interactieve shell in de profielmap bewijst niets over een verpakte unit. Beheerders stellen hun eigen werkmap in, en een wrapperscript kan die opnieuw wijzigen voordat de binary draait. De unit die faalt, is de enige start waarover het de moeite loont te redeneren.

systemctl show -p WorkingDirectory -p ExecStart --value openvpn@tenant-a
ls -l /proc/$(pgrep -n openvpn)/cwd

Het tweede commando toont de map die het levende proces werkelijk vasthoudt, en dat is betrouwbaarder dan het unit-bestand wanneer er een wrapper in het spel is. Als beide het oneens zijn, is de wrapper je antwoord en is de unit een dwaalspoor.

Na het opzoeken: rechten, chroot en sandbox

Een juiste basismap kan nog steeds dezelfde melding geven, omdat oplossing en toegang aparte stappen zijn. Het proces heeft uitvoerrechten op elke bovenliggende map nodig en leesrechten op het bestand, en een service-unit die een deel van het bestandssysteem verbergt, verandert wat het proces helemaal kan zien.

Drie gangbare varianten geven dezelfde fout. Het bestand is alleen voor root leesbaar terwijl de dienst voor het openen rechten laat vallen. De unit zet een beschermende bestandssysteemweergave op die de profielmap niet bevat. De daemon draait met chroot, dus het pad dat op de host bestaat, bestaat binnen die weergave niet.

Diagnostiseer met het eigenaarschap van het bestand en de identiteit van het proces, niet door rechten te versoepelen. Een persoonlijke sleutel voor iedereen leesbaar maken om deze fout te dempen, ruilt een luide storing in voor een stille, en de sleutel is juist het deel van de map dat je het minst wilt blootleggen.

Bewijs de oplossing met je eigen start

Herstart de echte unit vanuit een map die niets met het profiel te maken heeft en kijk naar dezelfde startregel. Bevestig daarna dat het proces tijdens het draaien de bedoelde map vasthoudt, en dat het certificaat dat het laadde het verwachte is.

systemctl restart openvpn@tenant-a
systemctl status openvpn@tenant-a --no-pager
journalctl -u openvpn@tenant-a -n 20 --no-pager

Als het laden van paden slaagt, blijven authenticatie en routering aparte fasen met hun eigen storingen, en een verbinding die opkomt maar geen verkeer doorlaat, is een ander onderzoek. De oplossing hier gaat alleen over uit welke map de bestanden kwamen, en die moet in de aanroep zichtbaar zijn in plaats van onthouden te worden door wie hem de vorige keer met de hand startte.

Als het profiel door een configuratiebeheerder wordt uitgerold, zet de basismap of de absolute bestandsnamen daar dan ook. Een handmatige oplossing op één host is de versie van dit probleem die na de volgende herbouw terugkomt.

Gerelateerde artikelen