AnyConnect unter Linux: die Anmeldesequenz sicher skripten
Die AnyConnect-vpn-Binärdatei liest Antworten aus stdin, und das reicht für eine wiederholbare Anmeldung. Baue die Sequenz, schütze die Datei, prüfe sie und höre auf.
Der vpn-Client, der mit Cisco AnyConnect ausgeliefert wird, verhält sich wie ein Gespräch: Er gibt eine Eingabeaufforderung aus, wartet auf eine Zeile, dann gibt er die nächste aus. Speist man dieses Gespräch aus einer Datei oder einer Pipe ein, läuft dieselbe Binärdatei unbeaufsichtigt. Die Technik besteht aus einer Umleitung plus einer geordneten Liste von Antworten, und es ist die Liste, nicht die Umleitung, die entscheidet, ob das Skript zuverlässig ist.
Zwei Dinge machen das in der Praxis kaputt. Die Reihenfolge der Eingabeaufforderungen verschiebt sich, wenn ein Gateway etwas Zusätzliches fragt, und ein gespeichertes Passwort verwandelt einen Tippfehler in eine Kontosperre. Behandle die Sequenz als versionierte Daten, die du nach jeder Gateway-Änderung vergleichen kannst. Scheitere laut, statt es erneut zu versuchen, denn eine Schleife ist genau der Weg, auf dem ein falsch getipptes Passwort zu einem gesperrten Konto wird.
Eine Sequenz, in der Reihenfolge, in der der Client fragt
Starte den Client einmal interaktiv und schreibe jede Eingabeaufforderung in der Reihenfolge auf, in der sie erscheint. Dieses Transkript wird die Antwortdatei. Wenn du die Datei in die Binärdatei umleitest, muss die erste Zeile der Verbindungsbefehl selbst sein, deshalb beginnt die Sequenz mit einem Hostnamen statt mit einem Benutzernamen.
connect vpn.example.com
0
<username>
<password>
y
exit
Das nackte 0 wählt das erste Verbindungsprofil, wenn das Gateway eine Liste anbietet; nutze den Index, den dein Gateway ausgibt. Das y akzeptiert ein Anmeldebanner, also lösche diese Zeile, wenn es kein Banner gibt, und füge eine Zeile überall dort ein, wo dein Gateway eine zusätzliche Frage stellt. Das abschließende exit ist das, was den Client sauber beenden lässt, wenn die letzte Antwort verbraucht ist.
/opt/cisco/anyconnect/bin/vpn -s < anyconnect.txt
Der nicht-interaktive Modus ist hier nicht optional. Ohne -s kann der Client das Terminal übernehmen und umgeleitete Eingaben ignorieren; mit ihm werden die Antworten aus dem Strom gelesen und der Prozess kehrt zurück. Wo die Binärdatei erhöhte Rechte braucht, packe den Aufruf in sudo -n, damit das Skript sofort scheitert, statt an einer Passwortabfrage zu blockieren.
Wo die Antwortdatei leckt
Eine Datei mit einem Passwort ist ein Zugangsdatum, also gib ihr die Rechte eines solchen: Modus 600, im Besitz des Kontos, das den Job ausführt, und niemals in einem geteilten oder synchronisierten Verzeichnis. Erstelle sie mit bereits gesetztem Modus, statt sie hinterher zu korrigieren, denn eine Datei ist zwischen dem Schreiben und dem chmod kurz für alle lesbar.
install -m 600 /dev/null ~/.config/anyconnect.txt
chmod 700 ~/.config
Die andere Hälfte ist argv. Ein Passwort, das als Argument übergeben wird, ist für jeden lokalen Benutzer sichtbar, der Prozesse auflistet, und es landet auch in der Shell-Historie. Lies es stattdessen aus einem Dateideskriptor oder einer Umgebungsvariable und setze die Nutzlast in Anführungszeichen, damit die Shell nichts darin expandieren kann.
printf '%s\n' 'connect vpn.example.com' '0' "$VPN_USER" "$VPN_PASS" 'y' 'exit' \
| sudo -n /opt/cisco/anyconnect/bin/vpn -s
Achte auf das Quoting. In doppelten Anführungszeichen kann ein Passwort mit ! von einer interaktiven Shell expandiert werden, bevor der Client es überhaupt sieht, und der Fehler kommt als generischer event-not-found-Fehler an, der wie ein Protokollproblem aussieht.
Beweise den Tunnel, dann schließe ihn
Ein verbundener Zustand beweist nur, dass der Client glaubt, eine Sitzung zu haben. Wähle einen Host, der nur aus dem Firmennetz antwortet, und prüfe ihn einmal, bevor du irgendetwas anderes tust. Ein Fehler dort ist ein Routing- oder Policy-Fehler, und die Anmeldung erneut auszuführen wird daran nichts ändern.
/opt/cisco/anyconnect/bin/vpn state
curl -sS -o /dev/null -w '%{http_code}\n' --max-time 10 https://<internal-host>/
/opt/cisco/anyconnect/bin/vpn disconnect
Prüfe die Zustandsausgabe vor und nach dem Trennen. Ein Client, der mit einer veralteten Sitzung zurückbleibt, kann die nächste Verbindung verweigern, während das Skript noch Erfolg meldet, und dieser Fehlermodus ist unsichtbar, wenn du nur Exit-Codes ansiehst. Vergleiche die beiden Messungen, statt der zweiten allein zu vertrauen. Aliase im Shell-Profil reichen für den täglichen Gebrauch, während alles Geplante dieselbe Prüfung von Zugangsdaten und Identität verdient wie jeder andere unbeaufsichtigte Job.
Wenn eine feste Liste nicht mehr sicher ist
Eine Antwortdatei kodiert die heutige Reihenfolge der Eingabeaufforderungen. Ein geändertes Banner, eine erzwungene Passwortänderung oder eine Zweifaktor-Herausforderung machen daraus eine Schleife, die das Konto sperren kann, weshalb das Skript bei der ersten unerwarteten Antwort beenden muss, statt neu zu starten.
Fange ab, was der Client ausgegeben hat, gib einen Nicht-Null-Status zurück und lass den Aufrufer entscheiden. Wo das Gateway einen zweiten Faktor verlangt, ist die ehrliche Antwort, dass eine unbeaufsichtigte Anmeldung für dieses Profil nicht verfügbar ist, und nicht, dass die Sequenz eine Zeile mehr braucht.
Rotation gehört in dieselbe Prüfung. Wenn das Zugangsdatum gespeichert wird, entscheide, wer es lesen darf, wann es sich ändert und was es entfernt, wenn der Host neu aufgebaut wird. Ein Skript, das ein Jahr funktioniert, weil niemand das Passwort angefasst hat, ist kein Design, sondern ein Unfall, der auf eine Rotationsrichtlinie wartet.
Profile, die nicht AnyConnect sind
Zwei ältere Cisco-Zugangsstile werden mit diesem verwechselt. Ein vpnc-Profil fragt nach einer IPSec-ID, die eigentlich der Gruppenname ist, dann nach einem Gruppengeheimnis, dann nach deinen eigenen Zugangsdaten, und alle drei kommen von dem, der das Gateway betreibt. Legacy-Cisco-IPsec ist ein anderes Protokoll als AnyConnect, also kann vpnc keinen Dienst erreichen, der nur AnyConnect spricht; openconnect --protocol=anyconnect ist der offene Client für diese Aufgabe.
Eine .pcf-Datei beschreibt das ältere Clientprofil. Host, Gruppenname und Gruppenpasswort darin lassen sich in einem Client, der Cisco IPsec spricht, von Hand neu eingeben, obwohl die Datei kein universeller Import ist und jeder Nicht-Standard-Port oder Tunnelmodus beim Transfer meist verschwindet.
Beginne mit dem, was das Gateway tatsächlich anbietet, und wähle dann den Client, der dieses Protokoll spricht. Ein Profil von einer anderen Site zu kopieren ist der Weg, auf dem Leute anfangen, Zugangsdaten zu debuggen, die nie das Problem waren.