Скрипт auth-user-pass-verify в OpenVPN: правильний код виходу
Статус виходу хука — це рішення, а не рядок журналу. Зіставте результати верифікатора з 0, 1 або відкладеною перевіркою, читайте файл облікових даних як дані та відмовляйте при помилці.
OpenVPN діє рівно за одним виходом скрипта входу: за статусом виходу. Усе інше, що робить скрипт, — оздоблення. Хук може дійти до потрібного верифікатора, розібрати відповідь і надрукувати привітний рядок, але повернути статус, що означає протилежне задуманому автором. Прочитайте спершу контракт і напишіть адаптер навколо нього, і весь цей клас помилок зникає.
Контракт невеликий: визначте надісланий обліковий запис, запитайте в затвердженого верифікатора потрібне питання і приймайте лише документований позитивний результат цього верифікатора для цього запиту. Усе інше — інфраструктура.
Три статуси, які хук може повернути
Для auth-user-pass-verify посібник OpenVPN 2.6 визначає код виходу 0 як прийняття, 1 як відмову і 2 як відкладену автентифікацію. Це єдині три відповіді, які розуміє сервер, і кожна має різні наслідки для з’єднання. Скрипт, що завершується статусом останньої команди, фактично дозволив виклику журналювання або кроку очищення проголосувати. Записуйте статус явно в кожній гілці, включно з гілками, які так і не дійшли до верифікатора.
Успіх HTTP і успіх автентифікації — різні рівні, і їх змішування є найчастішою причиною помилки цього хука. Відповідь 202 означає, що запит прийнято в обробку, а не що пароль перевірено. Визначте очікуваний статус, форму відповіді та остаточний вердикт із наданого вам контракту API і не вигадуйте назву поля лише тому, що вона виглядає правдоподібно.
Якщо відповідь справді надходить пізніше, це відкладений шлях, і його треба будувати саме так. Відкладена спроба, яка ніколи не завершується, утримує ресурси до завершення тайм-ауту.
Читайте файл облікових даних точно так, як його записано
За документованим методом через файл сервер записує ім’я користувача й пароль першими двома рядками тимчасового файлу, передає цей шлях скрипту й видаляє файл, коли скрипт повертається. Читайте ці два рядки як дані: ніколи не підключайте файл через source, не виконуйте його і не вставляйте його вміст у командний рядок, де його побачить таблиця процесів. Зберігайте пароль байт за байтом, бо нормалізація, яку ви застосували б до імені користувача, тихо змінює облікові дані. Каталог для цього тимчасового файлу — рішення розгортання, тому переконайтеся, що він існує і не читається всіма на хості.
Тримайте власні облікові дані верифікатора окремо від користувацьких: вони належать інтеграції зі шлюзом, живуть у сховищі секретів платформи і потребують лише права перевіряти, тому не є доказом того, що автентифікувалася конкретна особа. Не дозволяйте хуку стати й другим верифікатором паролів. Ручне переписування порівняння хешів не стає безпечним від оптимізації циклу, а підтримуваний верифікатор уже розуміє сольову й дорогу схему сховища облікових записів.
Вирішіть, що означає некласифікована відповідь
Тайм-аути, помилки транспорту, викривлені відповіді та недоступний бекенд мають одну спільну властивість: жоден із них не є позитивною перевіркою. Хук має закрито відмовляти за кожного з них і записувати причину, за якою оператор може діяти. Ця причина належить захищеному журналу, а не повідомленню, що повертається людині, яка намагається підключитися.
Будьте так само уважні до шляхів, які взагалі не доходять до верифікатора. Відсутнє значення конфігурації, нечитний секрет або невстановлена залежність мають давати відмову з окремою операційною позначкою, а не випадкове прийняття. Перевіряйте такі гілки, вилучаючи залежність у лабораторії, а не розмірковуючи про них. Там, де збій журналювання може змінити статус виходу, журналювання стало частиною рішення, і його треба зробити нешкідливим.
Конфігурація сервера тут також важлива: визначені користувачем скрипти враховуються лише тоді, коли робоча конфігурація дозволяє їх на потрібному рівні безпеки, і це налаштування — свідомий вибір, а не значення за замовчуванням, яке слід підвищити.
Перевіряйте вердикт, а не надрукований рядок
Побудуйте тест, який безпосередньо перевіряє статус виходу. Напишіть зразок файлу облікових даних, запустіть на ньому хук із завідомо добрим і завідомо поганим обліковим записом і читайте статус, який повідомляє оболонка, а не текст, який друкує скрипт. Ця єдина перевірка ловить більшість помилок контракту ще до того, як клієнт підключиться.
Потім проганьте ті самі випадки через справжнього клієнта проти неробочого слухача і підтвердьте, що записав сервер: прийнято, відхилено або відкладено. Охопіть вимкнений обліковий запис, неправильний пароль, викривлену відповідь верифікатора, тайм-аут і недоступний верифікатор. Якщо якийсь випадок потрапляє в стан, який ви не можете назвати, адаптер не завершено.
Тримайте відповідність результату верифікатора статусу виходу поруч зі скриптом у репозиторії, щоб наступний інженер міг прочитати контракт без зворотної розробки коду.