OpenVPN запрашивает имя пользователя и пароль на управляющем терминале, а файл, перенаправленный на стандартный ввод, — не этот терминал. Именно эта деталь объясняет скрипт, который зависает, хотя пароль лежит прямо в канале. Приглашение рисует клиент, а чтение идёт с терминального устройства, поэтому перенаправление stdin ничего не меняет. Подайте клиенту данные через один из его документированных входов, и тот же скрипт подключится с первой попытки.

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

Приглашение приходит не из stdin

Когда OpenVPN нужны учётные данные, он открывает управляющий терминал и читает оттуда. Поэтому интерактивная проверка выглядит нормально, а та же команда под cron или в unit-файле стоит без движения, с приглашением, записанным в журнал, куда никто не смотрит. Некоторые сборки откатываются на стандартный ввод, когда терминала нет, и эта несогласованность хуже жёсткой ошибки, потому что скрывает проблему до развёртывания.

Проверьте окружение до того, как писать код: запустите клиент под тем же пользователем, с тем же stdin, что и планировщик или менеджер служб. Если приглашение так и не появляется в журнале, а процесс не продвигается, что-то ждёт терминал, которого нет.

Первый вход: файл учётных данных из двух строк

Опция аутентификации принимает путь, и файл содержит ровно две строки: сначала имя пользователя, затем пароль, и больше ничего. Указывайте путь явно, а не полагайтесь на имя файла по умолчанию, потому что забытый файл с учётными данными в рабочем каталоге — это способ, которым в дело попадает не та учётная запись. Поставьте режим 0600 и отдайте владение учётной записи, которая запускает клиента.

Клиент читает этот файл один раз при запуске, так что смена пароля означает перезапуск процесса. Обычно это и нужно, и такое поведение заслуживает места в runbook рядом с процедурой смены.

Второй вход: askpass для парольной фразы ключа

Защищённый парольной фразой закрытый ключ вызывает второе, другое приглашение, и у него есть свой файловый ответ: опция askpass читает фразу из первой строки файла. Для туннелей на основе SSH эквивалент — программа askpass, которую запускает клиент и чей стандартный вывод становится секретом.

Ни одна из форм не кладёт секрет в список аргументов, и обе оставляют его существовать файлом или исполняемым файлом, который его печатает. Защита — это права файла и владение процессом, а не неочевидность. Помощник, который просто повторяет зашитую в код строку, — это секрет с лишними шагами.

Третий вход: собственный CLI портального клиента

Корпоративные клиенты обычно поставляют точку входа в командной строке, которая подключается к именованному порталу без окна, и это поддерживаемый путь. В Linux клиент GlobalProtect предоставляет операции подключения и импорта сертификата через свой CLI, а порталам с аутентификацией по сертификату нужен шаг импорта, прежде чем автоматическое подключение заработает. Предпочитайте его синтезированным нажатиям клавиш: вы получаете настоящий код выхода, отсутствие зависимости от фокуса окна, и он переживает заблокированный экран.

Если первому подключению всё ещё нужен человек, принимающий сертификат, автоматизация не закончена. Сделайте импорт при настройке и запишите его как предварительное условие.

Когда потоку нужен псевдотерминал

Последовательность, которая спрашивает пароль, а затем одноразовый код, не имеет одного файла для чтения. Драйвер терминала вроде Expect — правильный инструмент, потому что он ждёт каждый шаблон по очереди, и ему нужен запущенный процесс, прежде чем он вообще сможет что-то сопоставить.

Преобладают две ошибки. Скрипт, который ждёт приглашения, не запустив клиента, ждёт вечно, а Tcl — не оболочка, поэтому арифметика оболочки внутри блока expect не вычисляется так, как читается. Держите флаг отладки включённым, пока строите шаблоны, затем выключите его.

Секреты, которые утекают, и где они прячутся

Всё, что передано аргументом, видно в списке процессов, поэтому учётные данные должны быть в файле или за помощником, но не в командной строке. Одноразовые коды расходуются по замыслу и должны создаваться для каждой попытки. Журналы сбоев часто несут имя пользователя, а иногда и больше, поэтому отредактируйте их, прежде чем куда-то отправлять, и держите секрет вне самого профиля, потому что конфигурационный файл со встроенным паролем попадает в заявки и репозитории. Смена учётной записи тогда означает охоту за каждой копией, и именно этой цены избегает такая схема.

Проверьте выбранные входы, затем подключите их к unit-файлу или планировщику, который действительно будет запускать клиента. Туннель живёт ровно столько, сколько живёт этот процесс.

Похожие статьи