Як автоматизувати вхід у VPN, який чекає на код токена
Клієнт VPN у командному рядку, який запитує в терміналі, блокує скрипт, що передає лише пароль через канал. Виконайте ці п'ять перевірок, перш ніж братися за expect.
Скрипт, який запускає клієнт VPN від постачальника, зависає до вичерпання часу, а журнал показує, що клієнт просить код підтвердження, який ніхто не вводив. Пароль було передано, тож очевидний висновок — пароль неправильний. Це не так. Запит коду — окрема розмова на окремому каналі, і ваш скрипт жодного разу її не відкривав.
Пройдіть п'ять перевірок нижче по порядку. Зупиніться на першій невдалій, бо кожен наступний крок припускає, що попередні виконуються.
Перевірка 1: чи читає клієнт стандартний ввід узагалі?
Перевірте до написання будь-якої автоматизації: передайте клієнтові фіктивний секрет через канал і подивіться, що станеться. Якщо він друкує запрошення й далі чекає, канал він не читає.
Багато клієнтів відкривають пристрій термінала напряму або відмовляються брати секрет із потоку, який не є терміналом, щоб випадковий канал не міг злити пароль. OpenVPN — задокументований виняток, бо --auth-user-pass приймає шлях до файлу. Клієнти постачальників, які просять одноразовий код, зазвичай не мають еквівалентного прапорця, і їхнє запрошення чекає на термінал, якого ваш скрипт так і не надав.
Перевірка 2: чи має дочірній процес термінал?
pty виділяє дочірньому процессові термінал, що перетворює запрошення на читабельний вивід, на який можна відповідати по порядку.
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)Рядки запрошень вище — приклад; копіюйте точний текст, який друкує ваш клієнт, включно з регістром і пунктуацією. Кожне очікування має тайм-аут, а закритий дочірній процес кидає виняток замість повернення статусу, тож обгорніть послідовність і вважайте кінець файлу невдачею. Зверніть увагу, чого цей блок не робить: дочірній процес помирає разом зі скриптом, бо pty не є механізмом від'єднання, а disown — вбудована команда оболонки, яка не дістає до процесу, створеного вашим скриптом.
Перевірка 3: чи є підтримуваний неінтерактивний ввід?
Зчитування екрана ламається під час оновлень клієнта, тож спершу шукайте задокументований прапорець.
Перегляньте вивід довідки на наявність опції токена або одноразового коду й перевірте, чи приймає служба код, доданий до поля пароля. Там, де клієнт читає файл облікових даних, дайте йому файл замість запрошення:
openvpn --config office.ovpn --auth-user-pass <(printf "%s\n%s\n" "$USER_NAME" "$PASSWORD")Підстановка процесів дає клієнтові читабельний шлях у системах, які надають /dev/fd. Секрет залишається секретом з погляду клієнта, тож тримайте його поза журналами, історією оболонки та списками процесів. Якщо клієнт відкидає /dev/fd або відкриває шлях облікових даних більше одного разу, запишіть справжній файл із суворими правами й видаліть його в тому самому скрипті.
Перевірка 4: чи переживе тунель скрипт?
Типово тунель помирає разом зі своїм батьком, що протилежне тому, що потрібно скриптові запуску.
disown -h допомагає лише тоді, коли ви запустили клієнт як завдання оболонки, бо вона редагує таблицю завдань цієї оболонки й не дістає до процесу, створеного вашим скриптом через pty. Менеджер служб — краще місце для всього, що має перепідключатися без нагляду, бо він перезапускає клієнт і записує, чому той помер. У будь-якому разі після кожного перепідключення очікуйте новий код: одноразовий токен витрачається під час першої успішної автентифікації.
Стежте, що sudo робить із послідовністю. Запит пароля sudo — не запит VPN, і відповідь на нього паролем VPN — найпоширеніший спосіб, у який інакше правильний порядок очікувань усе одно ламається.
Перевірка 5: чи має код людини бути в скрипті?
Це перевірка, яку люди пропускають. Токен належить людині, а тунель, який має підніматися за розкладом, належить машині.
Якщо завдання має перепідключатися без нагляду, запитайте, чи може машинний сертифікат або службовий обліковий запис замінити інтерактивний вхід. Автоматизація чийогось одноразового коду перетворює другий фактор на збережений секрет, а це зміна політики, а не зручність для скриптів. Там, де служба підтримує обидва варіанти, виберіть облікові дані, що відповідають тому, як завдання насправді виконується. Запишіть відповідь, бо наступна людина запитає, чому скрипт тримає токен.
Як виглядає робочий скрипт
Скрипт друкує крок, до якого дійшов, ніколи не секрет, і завершується з ненульовим кодом за будь-якого невдалого очікування.
Перевірте його, навмисно зламавши: неправильний пароль, неправильна група, прострочений токен. Кожна невдача має зупинятися на названому кроці, а не зависати. Потім запустіть його один раз проти справжньої служби й перевірте тунель ззовні скрипта, а не зсередини.