Разрешаване на TLS passthrough връзка в контекста stream на NGINX
NGINX може да откаже TCP TLS релей, без да прекратява TLS. Поставете правилото за разрешение в stream, а не в HTTP location, и проверете кой адрес на партньора пристига.
Пренасочването на криптирани байтове, без никога да се държи сертификатът, е това, което прави TLS passthrough релеят, и подредбата е едновременно удобна и леко объркваща. Тъй като нищо не се дешифрира, няма нищо с форма на HTTP, по което да се филтрира, затова обичайният location блок и неговите правила за достъп тук са безполезни. Решението, с което NGINX разполага, е за самата връзка: кой мрежов партньор е почукал и дали този партньор изобщо трябва да бъде пропуснат.
Решението е в stream, не в HTTP
В контекста stream NGINX работи с TCP сесии. Той вижда адреса на партньора на връзката и може да приложи подредени правила allow и deny към него, преди каквито и да е байтове да стигнат до backend. Това е пълно решение за допускане и не изисква частен ключ, сертификат или HTTP анализ.
| Mechanism | What it decides | Where it lives |
|---|---|---|
| stream allow/deny | Whether this TCP peer is relayed | stream server block |
| ssl_preread map | Which backend a named connection goes to | stream, with the preread module |
| HTTP location rule | Whether an HTTP request is served | http 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.
Примерното правило покрива целия stream listener. Това го прави неподходящо за една входна точка, обслужваща смесица от публични сайтове и сайтове само за 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 да отговори и не може да поправи обратен път, който е липсвал преди началото.