Передавання зашифрованих байтів без володіння сертифікатом — це те, що робить релей TLS passthrough, і така схема зручна й водночас трохи заплутана. Оскільки нічого не розшифровується, немає нічого у формі HTTP для фільтрування, тому звичайний блок location та його правила доступу тут нічого не дають. Рішення, яке має NGINX, стосується самого з’єднання: який мережевий партнер постукав і чи слід його взагалі пропускати.

Рішення належить stream, а не HTTP

У контексті stream NGINX працює з TCP-сесіями. Він бачить адресу партнера з’єднання і може застосувати до неї впорядковані правила allow і deny, перш ніж будь-який байт досягне backend. Це повне рішення про допуск, і воно не потребує приватного ключа, сертифіката чи розбору HTTP.

MechanismWhat it decidesWhere it lives
stream allow/denyWhether this TCP peer is relayedstream server block
ssl_preread mapWhich backend a named connection goes tostream, with the preread module
HTTP location ruleWhether an HTTP request is servedhttp server block

Ці три рядки ніколи не замінюють один одного. Копіювання HTTP-директиви доступу до будь-якого файлу, де згадується порт 443, нічого не змінює, бо сервер stream ніколи не читає контекст http.

Прийміть з’єднання, перш ніж пересилати його

Припустімо, є наявна інсталяція з доступними модулями stream і stream-access, клієнти VPN тримають адреси джерела в 10.90.0.0/24, а backend на 192.168.50.20:443 уже надає потрібну ідентичність HTTPS.

stream {
    server {
        listen 443;

        allow 10.90.0.0/24;
        deny all;

        proxy_pass 192.168.50.20:443;
    }
}

Читайте це як фрагмент нового listener, а не як пряму заміну робочої конфігурації. Спершу перегляньте наявні listener та include, бо другий listener на вже зайнятому порту падає під час reload, а не під час запиту.

Зверніть увагу, чого немає: немає listen ... ssl, немає директиви сертифіката. NGINX пересилає зашифрований потік, а backend завершує TLS і подає сертифікат, який перевіряє клієнт. Клієнт, що не пройшов allowlist, отримує відхилену TCP-сесію, а не сторінку HTTP 403, і будь-який інструмент, що очікує код стану, повідомить щось марне.

Що охоплює allowlist, а що ні

Якщо релей уже вибирає backend за іменем сервера, ssl_preread і map можуть продовжувати цю роботу, за умови що модуль доступний. Ім’я все ще надає клієнт, і ніщо в поданні імені не доводить, що клієнт приєднався до VPN.

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

Варто назвати ще дві прогалини. Збіг префікса нічого не каже про те, через який інтерфейс надійшов пакет, а правило HTTP в іншому місці не може обмежити цей listener. Обидві причини тримати політику входу на рівні хоста в полі зору, а не вважати один рядок allow усією межею. Запишіть межу як два контролі, що мають збігатися, щоб зміна будь-якого з них проходила перевірку.

Чию адресу NGINX насправді бачить?

Балансувальник навантаження, інший proxy або source NAT можуть поставити посередника перед NGINX, тож спостережуваний партнер — не внутрішня адреса клієнта VPN. Перевірте реальний шлях, перш ніж вибирати префікс, бо allowlist, написаний для неправильної адреси, або пропускає всіх за транслятором, або нікого.

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

Перевірте обидва результати перед reload

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

nginx -t
ss -tnp | grep ':443'

Перевірте також маршрут до backend і відповідь окремо. Проходження allowlist доводить лише те, що NGINX прийняв сесію; воно не може змусити недоступний backend відповісти і не може виправити зворотний шлях, якого не було до початку.

Схожі статті