Sie brauchen keine temporäre Datei, um einen OpenVPN-Schlüssel zu erzeugen
Schlüsselmaterial im Speicher zu halten vermeidet einen Dateilebenszyklus, kein Leck. Trennen Sie Ausgabe- und Fehlerstrom, und behandeln Sie den Schlüssel danach als Geheimnis.
Die Schlüsselerzeugung braucht keine temporäre Datei, und sie wegzulassen behebt weniger, als die meisten Anleitungen andeuten. Was sie entfernt, ist ein Dateilebenszyklus und das Aufräumrennen darum herum. Was sie unberührt lässt, ist jede Gelegenheit, das Geheimnis danach zu verraten. Das Korrektheitsproblem in diesen Skripten sitzt meist woanders, weil Diagnose und Schlüsselmaterial auf verschiedenen Strömen reisen.
Die Datei war nie die Exposition, für die Sie sie hielten
Eine temporäre Datei ist ein konkretes Risiko, wenn sie für alle lesbar ist, wenn sie einen Absturz überlebt oder wenn ein Aufräumschritt nach einer Ausnahme übersprungen wird. Das ist real, und es lohnt sich, es zu beheben. Sie sind außerdem lokal, sichtbar und leicht zu testen. Benennen Sie jedes davon im eigenen Skript, bevor Sie schließen, die Änderung sei kosmetisch.
Die leiseren Risiken sitzen stromabwärts: der Schlüssel, der beim Debuggen ausgegeben wird, die Ausnahme, die das ganze Ergebnisobjekt serialisiert, der Absturzhandler, der einen Core-Dump schreibt, der Log-Aggregator, der den Dateipfad und dann den Inhalt erhält. Eine temporäre Datei zu vermeiden, tut für keines davon etwas, und das Gegenteil zu glauben ist der Weg, auf dem ein gut gemeintes Umschreiben das Geheimnis stärker exponiert lässt als zuvor. Behandeln Sie die Änderung als eine Verbesserung in einer Reihe, nicht als die Lösung.
Was der Client schreibt, wenn kein Dateiname angegeben wird
Aktuelle Versionen des Clients senden den erzeugten Schlüssel an die Standardausgabe, wenn der Schlüsselbefehl ohne Ausgabepfad angegeben wird. Genau dieses dokumentierte Verhalten macht den Ansatz im Speicher tragfähig, und es beseitigt die Notwendigkeit des älteren Kniffs, das Werkzeug auf einen Gerätepfad zu zeigen.
import subprocess
proc = subprocess.run(
["openvpn", "--genkey", "tls-crypt"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
check=True,
)
key_material = proc.stdout
Übergeben Sie den Befehl als Liste. Hier ist keine Shell-Expansion nötig, und eine Shell zu aktivieren würde die Argumentgrenze von Anführungszeichen abhängig machen, die Sie nicht kontrollieren. Verwenden Sie die vorgesehene ausführbare Datei über einen absoluten Pfad, wenn das Skript mit einem anderen Suchpfad laufen kann als erwartet.
Die Rückgabeprüfung verhindert, dass der Erfolgspfad nach einem fehlgeschlagenen Aufruf weiterläuft. Ohne sie kann ein leerer Byte-String weiterfließen und erst viel später scheitern, an der Stelle, an der der Schlüssel verwendet wird und die Fehlermeldung die Erzeugung gar nicht mehr erwähnt.
Zwei Ströme, zwei Bedeutungen
Die Standardausgabe trägt den Schlüssel. Der Standardfehler trägt alles, was das Werkzeug Ihnen sagen will, einschließlich Warnungen zur Konfiguration, zur Version und zum Schlüsseltyp. Beides in einen Puffer umzuleiten ist der Fehler, der einen plausibel aussehenden Schlüssel erzeugt, in dessen Mitte ein Satz eingenäht ist.
Halten Sie auch den Fehlerpfad getrennt. Wenn der Aufruf scheitert, melden Sie den gescheiterten Befehl und den Exit-Status und entscheiden Sie dann bewusst, ob irgendein Teil des Standardfehlers sicher anzuzeigen ist. Das vollständige Ergebnisobjekt in ein Log zu kippen ist die übliche Abkürzung, und sie kann den Schlüssel mitnehmen.
Ein binärsicheres Lesen ist wichtig, wenn Sie das Material später hashen oder vergleichen. Der Textmodus mit einer unerwarteten Kodierung kann Bytes verändern, die nie als Text gedacht waren, und ein veränderter Schlüssel ist von einem falschen nicht zu unterscheiden, bis ein Handshake scheitert.
Wenn Sie ihn doch speichern, dann bewusst
Die meisten Bereitstellungen brauchen den Schlüssel irgendwann auf der Platte, auf dem Gateway oder in einem Secret-Store. Schreiben Sie ihn einmal, mit restriktiven Rechten ab der Erstellung statt einem späteren chmod, und machen Sie das Schreiben atomar, damit eine teilweise Datei nie diejenige wird, die ein Dienst beim Start liest. Eine Umbenennung aus einem Pfad im selben Verzeichnis reicht dafür meist. Entfernen Sie den Staging-Pfad im Fehlerzweig, denn das fehlgeschlagene Schreiben ist genau die Kopie, die Leute vergessen.
Setzen Sie den Dateimodus beim Anlegen, und halten Sie auch den Verzeichnismodus restriktiv. Vermeiden Sie jeden Pfad unter einem Ort, den ein Backup-Job ohne Nachdenken mitnimmt, denn ein Geheimnis in einem nächtlichen Backup ist ein Geheimnis in jeder Kopie dieses Backups. Dieselbe Überlegung gilt für ein gemeinsam genutztes Volume, das andere Dienste lesen können.
Ein gemeinsamer Schlüssel ist keine Identität
Dieses Material zu erzeugen stellt kein Zertifikat aus, schreibt keinen Client ein und legt nicht fest, wer sich verbindet. Der gemeinsame Schlüssel schützt einen Kanal zwischen Parteien, die einander bereits vertrauen; Identität kommt weiterhin vom Zertifikat und von jeglicher Authentifizierung davor.
Die Schlüsseltypen sind ebenfalls nicht austauschbar. Ein symmetrischer Schlüssel für eine Funktion ist kein direkter Ersatz für eine andere, und neuere Versionen fügen eigene Varianten mit unterschiedlichen Dateien an jedem Ende hinzu. Erzeugen Sie den Typ, den Ihre Konfiguration tatsächlich nennt, und verwenden Sie ihn dann in der Rolle, die dieser Typ definiert.
Testen Sie das Ergebnis mit einer echten Verbindung statt durch Betrachten der Dateigröße. Wenn der Handshake abgeschlossen wird und die Logs keine Schlüsselwarnungen zeigen, ist der Erzeugungspfad richtig; wäre der Schlüssel durch einen zusammengelegten Strom abgeschnitten worden, würde die Verbindung so scheitern, dass sie auf die Gegenseite statt auf das Skript zeigt.