Je hebt geen tijdelijk bestand nodig om een OpenVPN-sleutel te genereren
Sleutelmateriaal in het geheugen houden vermijdt een bestandslevenscyclus, geen lek. Houd de uitvoer- en foutstroom gescheiden, en behandel de sleutel daarna als geheim.
Sleutelgeneratie heeft geen tijdelijk bestand nodig, en het overslaan ervan repareert minder dan de meeste handleidingen suggereren. Wat het wegneemt, is een bestandslevenscyclus en de opruimrace eromheen. Wat het onaangeroerd laat, is elke gelegenheid om het geheim daarna te lekken. Het correctheidsprobleem in deze scripts zit meestal elders, omdat diagnostiek en sleutelmateriaal over verschillende stromen reizen.
Het bestand was nooit de blootstelling die je dacht
Een tijdelijk bestand is een concreet risico wanneer het voor iedereen leesbaar is, wanneer het een crash overleeft, of wanneer een opruimstap na een uitzondering wordt overgeslagen. Die zijn echt, en het is de moeite waard ze te repareren. Ze zijn ook lokaal, zichtbaar en makkelijk te testen. Benoem elk ervan in je eigen script voordat je concludeert dat de wijziging cosmetisch was.
De stillere risico's zitten stroomafwaarts: de sleutel die tijdens het debuggen wordt afgedrukt, de uitzondering die het hele resultaatobject serialiseert, de crashhandler die een coredump schrijft, de logaggregator die het bestandspad en dan de inhoud ontvangt. Een tijdelijk bestand vermijden doet niets voor een van die, en het tegendeel geloven is hoe een goedbedoelde herschrijving het geheim kwetsbaarder achterlaat dan voorheen. Behandel de wijziging als één verbetering in een reeks, niet als de oplossing.
Wat de client schrijft als er geen bestandsnaam wordt gegeven
Huidige versies van de client sturen de gegenereerde sleutel naar de standaarduitvoer wanneer de sleutelopdracht zonder uitvoerpad wordt gegeven. Juist dat gedocumenteerde gedrag maakt de aanpak in het geheugen levensvatbaar, en het verwijdert de noodzaak van de oudere truc om het gereedschap op een apparaatpad te richten.
import subprocess
proc = subprocess.run(
["openvpn", "--genkey", "tls-crypt"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
check=True,
)
key_material = proc.stdout
Geef de opdracht als een lijst door. Hier is geen shell-expansie nodig, en een shell inschakelen zou de argumentgrens afhankelijk maken van aanhalingstekens die je niet beheert. Gebruik het bedoelde uitvoerbare bestand via een absoluut pad als het script met een ander zoekpad kan draaien dan je verwacht.
De returncodecontrole voorkomt dat het succespad doorgaat na een mislukte aanroep. Zonder die controle kan een lege bytereeks doorstromen en pas veel later falen, op het punt waar de sleutel wordt gebruikt en de foutmelding generatie helemaal niet meer noemt.
Twee stromen, twee betekenissen
De standaarduitvoer draagt de sleutel. De standaardfout draagt alles wat het gereedschap je wil vertellen, inclusief waarschuwingen over de configuratie, de versie en het sleuteltype. Beide naar één buffer omleiden is de fout die een plausibel uitziende sleutel oplevert met een zin in het midden genaaid.
Houd ook het foutpad apart. Wanneer de aanroep mislukt, meld dan de opdracht die mislukte en de exitstatus, en beslis daarna bewust of enig deel van de standaardfout veilig is om te tonen. Het volledige resultaatobject in een log dumpt is de gebruikelijke snelkoppeling, en die kan de sleutel meenemen.
Binair veilig lezen is belangrijk als je het materiaal later hasht of vergelijkt. Tekstmodus met een onverwachte codering kan bytes veranderen die nooit als tekst bedoeld waren, en een gewijzigde sleutel is niet te onderscheiden van een verkeerde tot een handshake mislukt.
Als je het toch opslaat, doe het dan bewust
De meeste implementaties hebben de sleutel uiteindelijk op schijf nodig, op de gateway of in een geheimopslag. Schrijf hem één keer, met beperkende rechten vanaf het aanmaken in plaats van een latere chmod, en maak het schrijven atomair zodat een gedeeltelijk bestand nooit het bestand wordt dat een dienst bij het starten leest. Een hernoeming vanaf een pad in dezelfde map is daar meestal genoeg voor. Verwijder het stagingpad op de fouttrap, want het mislukte schrijven is precies de kopie die mensen vergeten.
Stel de bestandsmodus in bij het aanmaken, en houd ook de mapmodus beperkend. Vermijd elk pad onder een locatie die een backuptaak zonder nadenken meeneemt, want een geheim in een nachtelijke backup is een geheim in elke kopie van die backup. Dezelfde redenering geldt voor een gedeeld volume dat andere diensten kunnen lezen.
Een gedeelde sleutel is geen identiteit
Dit materiaal genereren geeft geen certificaat uit, schrijft geen client in en stelt niet vast wie er verbindt. De gedeelde sleutel beschermt een kanaal tussen partijen die elkaar al vertrouwen; identiteit komt nog steeds van het certificaat en van elke authenticatie die daarvoor staat.
De sleuteltypen zijn ook niet uitwisselbaar. Een symmetrische sleutel voor één functie is geen directe vervanging voor een andere, en nieuwere releases voegen hun eigen varianten toe met verschillende bestanden aan elk uiteinde. Genereer het type dat je configuratie werkelijk noemt, en gebruik het dan in de rol die dat type definieert.
Test het resultaat met een echte verbinding in plaats van de bestandsgrootte te inspecteren. Als de handshake voltooit en de logs geen sleutelwaarschuwingen tonen, is het generatiepad juist; als de sleutel door een samengevoegde stroom was afgekapt, zou de verbinding op een manier falen die naar de tegenpartij wijst in plaats van naar het script.