Хук client-connect в OpenVPN: куди насправді потрапляє ваша адреса
Скрипт client-connect не може повернути адресу, просто надрукувавши її. Подивіться, як тимчасовий файл хука, код виходу та топологія визначають IP-адресу клієнта.
Повернення адреси зі скрипта client-connect виглядає так, ніби він має задати IP-адресу клієнта. Але ні: єдиний канал хука до сервера — це тимчасовий файл, шлях до якого надходить останнім аргументом скрипта, і адресу треба записати туди в синтаксисі ifconfig-push. Скрипт, який друкує адресу або завершується з нулем, нічого не записавши, створює підключеного клієнта з адресою з пулу, а журнал сервера виглядає цілком здоровим.
Плутанина зрозуміла, бо кілька інших хуків справді відповідають через коди виходу або змінні середовища. Цей має власний контракт, і контракт починається з імені файлу.
Хук записує файл, а не значення, що повертається
Оголошення складається з двох рядків: script-security 2, щоб дозволити виклик, потім client-connect /etc/openvpn/server/assign-address.sh. Коли клієнт проходить автентифікацію, сервер запускає цей скрипт, додаючи згенерований шлях до файлу останнім аргументом; він буде $1 лише якщо оголошення не передає власних додаткових аргументів. Усе, що застосовується до цього клієнта, записується в той файл звичайними директивами, по одній у рядку, точно так, як вони виглядали б у конфігурації. Обгортка, що додає свої параметри, зсуває позицію, і класичний симптом — скрипт, який пише за шляхом, схожим на --verbose.
Код виходу — друга половина контракту. Нуль означає прийняти й прочитати файл; будь-що інше відхиляє з'єднання, і саме так невідображена ідентичність отримує відмову замість тихого повернення до пулу. Запишіть повну директиву перед поверненням успіху, щоб напівзаписаний файл ніколи не став конфігурацією клієнта.
Дві директиви варті уваги, бо вони взаємодіють з усім іншим. ifconfig-push фіксує адресу, а надісланий route повідомляє клієнту, що доступне через тунель; поверніть першу й забудьте другу — отримаєте клієнта з адресою і без місця, куди йти. Порядок у файлі не важливий, а повнота важлива. Хук, що надсилає маршрут для префікса, до якого не дістанеться жоден партнер, — та сама помилка з іншого боку.
Вхідні дані надходять через змінні середовища: common_name, trusted_ip, ifconfig_pool_remote_ip та інші. Ставтеся до всіх них як до рядків ззовні сервера, ніколи як до фрагментів оболонки.
Зіставлення адрес — це політика, а не арифметика
Спокусливий короткий шлях — розібрати ім'я сертифіката й використати його цифри як останній октет. Це не розподільник, і він відмовляє звичайними способами: два імені з однаковим суфіксом конфліктують, ім'я, що закінчується на 300, не є адресою, а сертифікат, перейменований адміністратором, тихо переміщує пристрій. Перевіряйте належність до підмережі, придатний діапазон хостів, зарезервовані адреси та унікальність під час кожного виклику, а зіставлення тримайте в таблиці, яку людина може прочитати.
Хто керує іменем, той керує адресою, тож вирішіть, що common_name насправді представляє в цьому розгортанні. Коли ввімкнено username-as-common-name, ідентичність — це логін, а не суб'єкт сертифіката. Ніколи не передавайте це значення в обчислення оболонки й ніколи не дозволяйте клієнту впливати на шлях до файлу.
Розподільник на основі реєстру має витримувати конкурентність. Резервуйте адресу атомарно, обробляйте невдалий запис, не допускаючи напівналаштованого клієнта, і позначайте кожне виділення з'єднанням, якому воно належить, щоб пізнє від'єднання старої сесії не могло звільнити адресу, яку вже тримає новіша. Кілька екземплярів сервера, що ділять один пул, роблять цю вимогу гострішою, а не необов'язковою.
Топологія визначає, що означає ifconfig-push
З topology subnet на 10.77.0.0/24 ifconfig-push 10.77.0.20 255.255.255.0 — це адреса плюс її маска мережі. За topology net30 другий аргумент зовсім не маска, а адреса партнера, тож копіювання форми підмережі на сервер net30 дає клієнта, який підключається й не може пропускати трафік. Змінюйте топологію свідомо, ніколи не для того, щоб приклад виглядав узгоджено. Сервер, який уже працює з net30, має живих клієнтів на старій адресації, тож перемикання — це міграція з вікном обслуговування, а не правка одного рядка.
Статичні адреси мають бути поза динамічним пулом і поза кожним іншим статичним призначенням, включно з тими, що їх видають звичайні файли client-config-dir. Якщо два механізми можуть видати ту саму адресу різним клієнтам, один із них зрештою це зробить.
Перевірте чотири випадки, перш ніж довіряти цьому
Запустіть ті самі перевірки для зіставленої ідентичності, незіставленої, повторного підключення та змодельованого збою реєстру. openvpn --config client.ovpn --verb 4 показує призначену адресу у відповіді push, а на сервері grep -A2 PUSH_REPLY /var/log/openvpn/openvpn.log підтверджує, що фактично надіслано. Для незіставленої ідентичності очікуваний результат — відхилене з'єднання, а не адреса з пулу.
Далі огляньте каталог, у який демон пише ці тимчасові файли. Скрипт виконується в зниженому контексті служби, тож шлях, доступний для запису root, але не демону, перетворює кожне з'єднання на відмову з помилкою прав, похованою кількома рядками нижче в журналі.
Виділення — це не авторизація: закріплена адреса все одно не дає доступу до кожного призначення за сервером. Тримайте політику маршрутизації та брандмауера в її власному шарі й перевіряйте її щодо адреси, яку ви щойно закріпили.