Как да автоматизирате VPN вход, който чака код за токен
CLI клиент на 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: трябва ли кодът на човек да е в скрипт?
Това е проверката, която хората пропускат. Токенът принадлежи на човек, а тунелът, който трябва да се вдига по график, принадлежи на машината.
Ако дадена задача трябва да се свързва отново без надзор, попитайте дали машинен сертификат или служебен акаунт може да замени интерактивното влизане. Автоматизирането на нечий еднократен код превръща втория фактор в запазена тайна, което е промяна в политиката, а не удобство за скриптове. Когато услугата поддържа и двете, изберете идентификационните данни, които отговарят на това как задачата реално работи. Запишете отговора, защото следващият човек ще попита защо скриптът държи токен.
Как изглежда работещ скрипт
Скриптът отпечатва стъпката, до която е стигнал, никога тайната, и излиза с ненулев код при всяко неуспешно очакване.
Тествайте го, като го счупите нарочно: грешна парола, грешна група, изтекъл токен. Всеки провал трябва да спре на именувана стъпка, вместо да виси. След това го пуснете веднъж срещу реалната услуга и проверете тунела отвън, а не отвътре на скрипта.