Запуск nc -uz проти OpenVPN сервера майже нічого не вимірює, і посібник OpenBSD каже про це у своїх застереженнях: UDP-сканування в цьому режимі повідомляє про успіх незалежно від того, чи щось слухає. Код виходу відображає локальне надсилання, а не віддалений стан, тому супервізор, який йому довіряє, тримає мертвий сервер позначеним як здоровий, доки таблиця процесів виглядає правдоподібно. Заміна починається з рішення, на яке питання має відповісти перевірка, бо процес, слухач, автентифікація та доступність застосунку — це чотири різні спостереження. Перевірка, що називає одне з них, корисна; перевірка, що передбачає всі чотири, — тягар.

Що UDP-перевірка може і чого не може спостерігати

nc -uz надсилає дейтаграму і завершується, а повернутий статус описує локальне надсилання. Зачинений порт може відповісти ICMP port unreachable, але задокументована поведінка цього режиму сканування не перетворює це на помилку, а відфільтрований порт взагалі не дає відповіді. Тому тиша й успіх означають для того, хто викликає, одне й те саме.

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

Узгодження перевірки з налаштованим транспортом іде до довіри до будь-якого з двох результатів. Розгортанню з UDP потрібен інший сигнал, а не інший протокол.

Три викликачі, три різні питання

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

Це не та сама перевірка, і одна перевірка не може чесно покрити всі три. Спершу виберіть викликача, потім доказ.

Побудуйте перевірку з поточного екземпляра

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

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

systemctl is-active openvpn@server
sudo journalctl -u openvpn@server -b --no-pager | grep "Initialization Sequence Completed"
ss -lunp | grep 1194

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

Зламайте це навмисно і поспостерігайте за перевіркою

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

sudo systemctl stop openvpn@server
nc -uz 203.0.113.10 1194; echo "exit=$?"
ss -lunp | grep 1194
sudo systemctl start openvpn@server
ss -lunp | grep 1194

Читайте блок рядок за рядком. Команда netcat друкує exit=0 , хоча нічого не прив’язано, і це вся проблема в одному рядку. Перша ss нічого не друкує, перезапуск вдається, а друга ss знову показує слухача. Якщо ваша перевірка проходить проти зупиненого сервера, вона вимірює локальний стек і більше нічого.

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

Що має казати рядок стану

Запишіть, яку межу покриває кожна перевірка: процес, слухач, автентифікацію чи застосунок. Одна перевірка рідко покриває більше ніж одну, а сторінка стану, що стискає їх у “up”, приховує різницю, важливу під час інциденту. Для мережевого шляху використовуйте реального клієнта з виділеною ідентичністю, дайте йому завершити рукостискання й одну нешкідливу дозволену операцію, потім від’єднайте. Це тренує канал керування, політику автентифікації та слухача за один крок.

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

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

Схожі статті