Переконання полягає в тому, що here-документ із чотирьох рядків — це повноцінний неінтерактивний вхід, і воно тримається рівно до того моменту, коли шлюз запропонує дві групи, надрукує банер або запитає токен після пароля. Тоді той самий сценарій вводить пароль у меню, яке чекало числа. Клієнт командного рядка в Linux піддається сценаріям, але лише якщо ви дасте йому те, чого він справді чекає, а не те, що припускав посібник.

Фіксований here-документ — це міф

Клієнт Cisco для Linux установлює невелику програму в /opt/cisco/anyconnect/bin/vpn, і Secure Client 5 досі її постачає. Поки служба vpnagentd працює, прапорець -s читає відповіді зі стандартного входу в тому порядку, у якому клієнт їх запитує. Цей порядок не фіксований між серверами.

Меню груп додає один рядок. Банер входу додає ще один. Запит токена після пароля повністю ламає сценарій із чотирьох рядків, бо п’ятий рядок ніколи не мав бути токеном. Збій тихий: клієнт отримує неправильний рядок, спроба з’єднання завершується, а сценарій не повідомляє нічого корисного.

Запустіть клієнт вручну один раз проти того самого шлюзу й версії та запишіть запрошення в порядку їх появи. Цей запис — специфікація, якій має відповідати ваш сценарій.

Чого чекає клієнт

У звичайному випадку однієї групи послідовність така: ім’я користувача, пароль і іноді підтвердження банера. Перший рядок here-документа стає індексом меню лише тоді, коли сервер справді показує меню, тому той самий сценарій працює на одному сайті й зривається на наступному.

/opt/cisco/anyconnect/bin/vpn -s connect vpn.example.net <<EOF
0
alice
$VPN_PASSWORD
y
EOF

Читайте це як чотири відповіді на чотири можливі питання, а не як фіксований протокол. Нуль — це вибір меню, а не пароль, а завершальна y приймає банер, який багато шлюзів ніколи не надсилають.

Використовуйте expect, коли порядок непередбачуваний

Коли порядок запрошень змінюється, перестаньте рахувати рядки й натомість чекайте на запрошення. Сценарій expect запускає команду connect, чекає запрошення імені користувача, надсилає, чекає запрошення пароля, надсилає, а потім чекає стану з’єднання. Кожне очікування має власний тайм-аут.

Вважайте тайм-аут збоєм і виходьте. Сценарій, який продовжує надсилати введення після неочікуваного запрошення, із задоволенням введе пароль в оболонку, меню або що завгодно інше, що читає. Так сценарій входу перетворюється на інцидент.

Expect також дає запис, який можна залогувати з вилученим секретом, і це цінніше за код виходу, коли шлюз після оновлення змінює свої запрошення.

Секрет має десь жити

Кожна версія цієї проблеми має одну слабкість: пароль має існувати у формі, яку клієнт може прочитати. Передача його аргументом розкриває його в таблиці процесів. Виведення через конвеєр часто потрапляє в історію оболонки. І те, і те читають інші локальні користувачі на спільному проміжному хості.

install -m 600 /dev/null ~/.vpn-secret
umask 077; VPN_PASSWORD=$(cat ~/.vpn-secret) /opt/cisco/anyconnect/bin/vpn -s connect vpn.example.net

Файл із режимом 600, що належить обліковому запису, — це мінімум, і він усе ще секрет відкритим текстом на диску. secret-tool lookup читає зі зв’язки ключів Linux, а в macOS ту саму роботу виконує security find-generic-password -w. Там, де організація підтримує автентифікацію сертифікатом або SAML, надавайте перевагу їй, бо збережений пароль плюс MFA все одно не завершить вхід без людини.

Підтвердьте тунель, а потім візьміть розрив на себе

Не довіряйте відсутності тексту помилки. Запитайте у клієнта його стан і перевірте інтерфейс незалежно:

/opt/cisco/anyconnect/bin/vpn state
ip -brief address

Стан має читатися як Connected, а інтерфейс тунелю має мати адресу. Потім запитайте один ресурс, до якого тунель має дістатися, бо під’єднаний стан без маршруту — реальний результат, і його легко не помітити.

Відключайтеся через vpn disconnect і дозвольте сценарію, що запустив тунель, взяти розрив на себе. Невдала задача, яка залишає сеанс відкритим, витрачає місце ліцензії й виглядає як проблема автентифікації для наступного, хто спробує.

Порядок роботи: підтвердьте vpnagentd, зафіксуйте реальний порядок запрошень, виберіть here-документ або expect, тримайте секрет поза argv та історією, перевірте стан і один ресурс, потім відключіться в тому самому сценарії.

Схожі статті