Ein Skript, das einen VPN-Client eines Anbieters startet, hängt, bis es in einen Timeout läuft, und das Protokoll zeigt, dass der Client nach einem Bestätigungscode fragt, den niemand eingegeben hat. Das Passwort wurde übergeben, also ist die naheliegende Schlussfolgerung, dass das Passwort falsch ist. Ist es nicht. Die Codeabfrage ist ein separates Gespräch auf einem separaten Kanal, und Ihr Skript hat ihn nie geöffnet.

Arbeiten Sie die fünf Prüfungen unten der Reihe nach durch. Bleiben Sie bei der ersten stehen, die fehlschlägt, denn jeder spätere Schritt setzt voraus, dass die früheren gelten.

Prüfung 1: Liest der Client überhaupt die Standardeingabe?

Testen Sie, bevor Sie irgendeine Automatisierung schreiben: Schicken Sie ein Dummy-Geheimnis durch eine Pipe in den Client und beobachten Sie, was passiert. Wenn er seine Abfrage ausgibt und dann wartet, liest er die Pipe nicht.

Viele Clients öffnen das Terminalgerät direkt oder weigern sich, ein Geheimnis aus einem Strom anzunehmen, der kein Terminal ist, damit eine verirrte Pipe kein Passwort preisgeben kann. OpenVPN ist die dokumentierte Ausnahme, weil --auth-user-pass einen Dateipfad annimmt. Anbieter-Clients, die nach einem Einmalcode fragen, haben meist kein entsprechendes Flag, und ihre Abfrage wartet auf ein Terminal, das Ihr Skript nie bereitgestellt hat.

Prüfung 2: Hat der Kindprozess ein Terminal?

Ein pty weist dem Kind ein Terminal zu, wodurch Abfragen zu lesbarer Ausgabe werden, die Sie der Reihe nach beantworten können.

import pexpect

child = pexpect.spawn("openconnect vpn.example.net", encoding="utf-8", timeout=30)
child.expect("GROUP:")
child.sendline("staff")
child.expect("USERNAME:")
child.sendline("alice")
child.expect("PASSWORD:")
child.sendline(PASSWORD)
child.expect("Connected as", timeout=60)

Die Abfragezeichenfolgen oben sind illustrativ; kopieren Sie den genauen Text, den Ihr Client ausgibt, einschließlich Groß- und Kleinschreibung und Satzzeichen. Jede Erwartung hat ein Zeitlimit, und ein geschlossenes Kind löst eine Ausnahme aus, statt einen Status zurückzugeben, also umschließen Sie die Sequenz und behandeln Sie das Dateiende als Fehler. Beachten Sie, was dieser Block nicht tut: Das Kind stirbt mit dem Skript, weil ein pty kein Abkoppelmechanismus ist und disown eine Shell-Eingebaute ist, die einen von Ihrem Skript gestarteten Prozess nicht erreichen kann.

Prüfung 3: Gibt es eine unterstützte nicht-interaktive Eingabe?

Das Abgreifen des Bildschirminhalts bricht bei Client-Upgrades, also suchen Sie zuerst nach einem dokumentierten Flag.

Prüfen Sie die Hilfeausgabe auf eine Token- oder Einmalcode-Option und prüfen Sie, ob der Dienst den an das Passwortfeld angehängten Code akzeptiert. Wo der Client eine Anmeldedatendatei liest, geben Sie ihm die Datei statt einer Abfrage:

openvpn --config office.ovpn --auth-user-pass <(printf "%s\n%s\n" "$USER_NAME" "$PASSWORD")

Prozesssubstitution gibt dem Client einen lesbaren Pfad auf Systemen, die /dev/fd bereitstellen. Das Geheimnis bleibt aus Sicht des Clients ein Geheimnis, also halten Sie es aus Protokollen, der Shell-Historie und Prozesslisten heraus. Wenn der Client /dev/fd ablehnt oder den Anmeldedatenpfad mehr als einmal öffnet, schreiben Sie eine echte Datei mit strengen Rechten und löschen Sie sie im selben Skript.

Prüfung 4: Überlebt der Tunnel das Skript?

Standardmäßig stirbt der Tunnel mit seinem Elternteil, was das Gegenteil dessen ist, was ein Bootstrap-Skript braucht.

disown -h hilft nur, wenn Sie den Client als Shell-Job gestartet haben, weil es die Jobtabelle dieser Shell bearbeitet und einen Prozess nicht erreichen kann, den Ihr Skript über ein pty gestartet hat. Ein Dienstmanager ist das bessere Zuhause für alles, was unbeaufsichtigt neu verbinden muss, weil er den Client neu startet und festhält, warum er gestorben ist. Erwarten Sie in jedem Fall einen neuen Code nach jeder Neuverbindung: Ein Einmal-Token wird durch die erste erfolgreiche Authentifizierung verbraucht.

Achten Sie darauf, was sudo mit der Sequenz macht. Eine sudo-Passwortabfrage ist nicht die Abfrage des VPN, und sie mit dem VPN-Passwort zu beantworten ist der häufigste Weg, wie eine ansonsten korrekte Erwartungsreihenfolge trotzdem scheitert.

Prüfung 5: Sollte der Code einer Person in einem Skript stehen?

Das ist die Prüfung, die Leute überspringen. Ein Token gehört einer Person, während ein Tunnel, der nach Zeitplan hochkommen muss, der Maschine gehört.

Wenn ein Job unbeaufsichtigt neu verbinden muss, fragen Sie, ob ein Maschinenzertifikat oder ein Dienstkonto die interaktive Anmeldung ersetzen kann. Den Einmalcode von jemandem zu automatisieren macht aus einem zweiten Faktor ein gespeichertes Geheimnis, was eine Richtlinienänderung ist und keine Skriptbequemlichkeit. Wo der Dienst beides unterstützt, wählen Sie die Anmeldedaten, die dazu passen, wie der Job tatsächlich läuft. Schreiben Sie die Antwort auf, denn die nächste Person wird fragen, warum das Skript ein Token hält.

Wie ein funktionierendes Skript aussieht

Das Skript gibt den erreichten Schritt aus, niemals das Geheimnis, und beendet sich bei jeder fehlgeschlagenen Erwartung mit einem Nicht-Null-Code.

Testen Sie es, indem Sie es absichtlich kaputt machen: falsches Passwort, falsche Gruppe, abgelaufenes Token. Jeder Fehlschlag sollte an einem benannten Schritt stehen bleiben, statt zu hängen. Führen Sie es dann einmal gegen den echten Dienst aus und prüfen Sie den Tunnel von außerhalb des Skripts, nicht von innen.

Ähnliche Artikel