Яке джерело облікових даних використовувати, вирішують три речі: чи сидить людина за консоллю, чи може секрет жити на диску і чи має інший процес відповідати на запит. Якщо вибрати неправильно, клієнт повідомить про проблему зі stdin, хоча пароль цілком правильний, і це без причини відправляє більшість людей до сервера. Спершу виберіть шлях; повідомлення про помилки мають сенс лише тоді, коли ви знаєте, який шлях їх породив.

Три умови, що це вирішують

Запит у консолі — єдиний шлях, який потребує людини, тому він єдиний, що тихо зазнає невдачі в юніті systemd або в контейнері. Якщо людина запускає клієнт і вводить пароль, файл не задіяний і нічого чутливого не потрапляє на диск. Якщо клієнт запускається під час завантаження, той самий запит стає зависанням, і тайм-аут зазвичай виглядає як загальна помилка з'єднання, а не як помилка облікових даних.

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

  • Людина за консоллю, без автоматизації: інтерактивний запит.
  • Запуск без нагляду, секрет можна зберігати: файл облікових даних із режимом 0600.
  • Запуск без нагляду, секрет зберігати не можна: підстановка процесу або fd, у який пише агент секретів.
  • Клієнтом володіє інший процес: інтерфейс керування.

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

Що насправді робить кожен шлях введення

--auth-user-pass сам по собі запитує в консолі ім'я користувача й пароль. Якщо дати ім'я файлу, клієнт бере перший рядок як ім'я користувача, а другий як пароль; ніщо не підтримує лапки, коментарі або синтаксис ключ-значення. Це весь формат, тож кожен, хто редагує його, очікуючи файл INI, ламає його. Вбудований блок <auth-user-pass> містить ті самі два рядки в профілі, що робить сам профіль секретом і ставить його в той самий клас обробки, що й закритий ключ.

Решта два шляхи — це потік і сокет. OpenVPN потрібен лише читабельний файловий дескриптор, тож вона прийме підстановку процесу, запис /dev/fd на основі каналу або ім'я файлу, яке насправді є FIFO. Інтерфейс керування інший за природою: клієнт запитує значення в наглядового процесу замість того, щоб читати їх сам. Ця різниця важлива при повторному підключенні: файл облікових даних, FIFO, у який помічник секретів може писати знову, та інтерфейс керування можуть надати дані заново без людини; підстановка процесу не може, бо дескриптор витрачається при першому читанні.

Файл має бути рівно з двох рядків

Два режими відмови покривають більшість зламаних файлів облікових даних. Редактор Windows залишає закінчення CRLF, повернення каретки стає частиною пароля, і сервер відхиляє значення, яке на екрані виглядає правильним. Порожній другий рядок — порожній рядок там, де має бути пароль — залишає клієнт із порожнім паролем, який сервер відхиляє, хоча значення на екрані виглядає правильним. Зайвий перевід рядка після пароля нешкідливий. Записуйте файл із shell, а не з редактора, і перевіряйте байти:

install -m 600 /dev/null /etc/openvpn/client.creds
printf '%s\n%s\n' "$VPN_USER" "$VPN_PASS" > /etc/openvpn/client.creds
od -c /etc/openvpn/client.creds | head -3

Шлях так само важливий, як і вміст. Відносний шлях розв'язується відносно робочого каталогу процесу, який для служби рідко є каталогом, де ви тестували. Використовуйте абсолютний шлях, зробіть файл власністю облікового запису, що запускає клієнт, і тримайте режим 0600, щоб група та інші не могли його читати. Посібник OpenVPN 2.6 перелічує прийнятні форми директиви; перевірте його, перш ніж вигадувати третю.

Перевірте файл, перш ніж звинувачувати сервер. Запуск openvpn --config client.ovpn --auth-user-pass /etc/openvpn/client.creds --verb 4 друкує, чи файл було відкрито і згодом чи облікові дані прийнято, що підказує, який шар змінювати далі.

Потоки, stdin і помилки, які вони породжують

Передача пароля через канал — перше, що пробує більшість, і шлях із найбільшою кількістю сюрпризів. Підстановка процесу працює, бо клієнту потрібен лише читабельний дескриптор: openvpn --config client.ovpn --verb 3 --auth-user-pass <(printf '%s\n%s\n' "$VPN_USER" "$VPN_PASS"). Передача /dev/stdin працює тільки тоді, коли stdin у момент запиту клієнта ще відкритий і читабельний, що не так у конвеєрі, який його вже витратив.

ERROR: could not read Auth username from stdin має дві різні причини. У деяких клієнтах 2.3.x повідомлення походило з дефекту обробки stdin, який виправили пізніші випуски 2.3, тож такий старий клієнт покращується лише оновленням. У сучасному клієнті те саме формулювання означає, що клієнт запитав введення з консолі, а stdin не був терміналом — саме ситуація в юніті systemd, завданні cron або контейнері, запущеному без -t.

auth-nocache додає третій цикл, який виглядає як зламаний пароль. Він викидає облікові дані з пам'яті після використання, тож повторному підключенню, спричиненому зміною мережі, нема чого відтворювати, і запит повертається. Це директива, що працює як задумано. auth-nocache змінює те, що клієнт тримає в пам'яті, а не те, що сервер або постачальник ідентичності думає про обліковий запис, тож усе виправлення — знову надати той самий файл, перечитаний під час перезапуску, — а для керованого з'єднання це надання має надходити зі схваленого сховища секретів, а не з пароля в скрипті.

Інтерфейс керування, коли запитом володіє інший процес

Контролер, який уже наглядає за тунелем, може також відповідати на його питання. Запустіть клієнт із --management 127.0.0.1 7505, читайте рядки стану і стежте за >PASSWORD:Need 'Auth' username/password. Контролер відповідає username "Auth" alice, за чим іде password "Auth" ... окремими командними рядками. Токен 'Auth' повторює ідентифікатор із запиту і має збігатися, інакше відповідь ігнорується і клієнт чекає.

Ціна — це машина станів, якою ви тепер володієте: порядок з'єднань, перезапуски клієнта і локальний сокет, до якого інші користувачі на хості не повинні діставатися. Ви купуєте облікові дані, надані під час виконання, без файлу на диску і без запиту, що може зависнути. Якщо більше ніщо у вашому стеку вже не говорить цим протоколом, цей шлях додає компонент, який треба обслуговувати.

Збої, що виглядають як проблеми з обліковими даними

Рукостискання TLS, яке ніколи не завершується, або VERIFY ERROR: depth=0, error=certificate signature failure — це проблема довіри, і вона трапляється раніше, ніж читається будь-яке ім'я користувача. Клієнт proto tcp, скерований на UDP-слухача, зазнає невдачі в тому самому місці: пакети ніколи не доходять до етапу автентифікації, тож кожен пароль виглядає неправильним через асоціацію. Тримайте перевірку сертифікатів увімкненою до надсилання облікових даних; знайомий запит нічого не каже про те, хто отримує пароль. Перевірте ланцюжок сертифікатів, спільне ім'я і транспорт, перш ніж торкатися облікових даних.

Помилки shell у скрипті, що збирає профіль, — це інший хибний слід. Пропущений пробіл усередині [ ! -f "$file" ] породжує command not found, скрипт зупиняється рано, профіль ніколи не перебудовується, і клієнт стартує з попереднім. Ця помилка належить shell, а не автентифікації, і жодне переписування пароля її не прибере.

Не кожен запит у цьому потоці — це ці облікові дані. Парольна фраза закритого ключа, вхід через HTTP-проксі та пароль служби — це три різні секрети, що запитуються на різних етапах, і парольну фразу ключа зазвичай обробляє клієнт або агент, а не auth-user-pass. Якщо запит з'являється до встановлення сеансу TLS, ви відповідаєте на неправильне питання, і жодне скидання облікового запису не допоможе. Коли неправильний запит виключено, решта перевірок починається з найранішого шару:

  • Читайте першу помилку протоколу, а не останній рядок облікових даних: TLS, потім автентифікація, потім push.
  • Переконайтеся, що файл складається з двох рядків, не містить повернень каретки і вказаний абсолютним шляхом.
  • Переконайтеся, що профіль і командний рядок не розходяться щодо директиви.
  • Відокремте «облікові дані прийнято» від «трафік іде» — маршрутизація і DNS це пізніший шар.

Коли клієнт досягає етапу push, припиніть дивитися на облікові дані і почніть читати маршрути та DNS-сервери, які надіслав сервер. Це наступна проблема, і вона не має нічого спільного з паролем, який ви щойно виправили.

Схожі статті