Zezwalanie na połączenie TLS passthrough w kontekście stream NGINX
NGINX może odrzucić przekazywanie TCP TLS bez kończenia TLS. Regułę zezwolenia umieść w stream, a nie w location HTTP, i sprawdź, jaki adres peera przychodzi.
Przekazywanie zaszyfrowanych bajtów bez kiedykolwiek posiadania certyfikatu to właśnie robi relay TLS passthrough, a ten układ jest wygodny i jednocześnie nieco mylący. Ponieważ nic nie jest odszyfrowywane, nie ma nic w kształcie HTTP do filtrowania, więc zwykły blok location i jego reguły dostępu nic tu nie dają. Decyzja, którą ma NGINX, dotyczy samego połączenia: który peer sieciowy zapukał i czy w ogóle należy go przepuścić.
Decyzja należy do stream, nie do HTTP
W kontekście stream NGINX pracuje z sesjami TCP. Widzi adres peera połączenia i może zastosować do niego uporządkowane reguły allow i deny, zanim jakikolwiek bajt dotrze do backendu. To pełna decyzja o dopuszczeniu i nie wymaga klucza prywatnego, certyfikatu ani analizy 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 |
Te trzy wiersze nigdy się nie zastępują. Skopiowanie dyrektywy dostępu HTTP do pliku, który wspomina o porcie 443, nic nie zmienia, bo serwer stream nigdy nie czyta kontekstu http.
Dopuść połączenie, zanim je przekażesz
Załóż istniejącą instalację z dostępnymi modułami stream i stream-access, klientami VPN utrzymującymi adresy źródłowe w 10.90.0.0/24 oraz backendem pod 192.168.50.20:443, który już serwuje zamierzoną tożsamość HTTPS.
stream {
server {
listen 443;
allow 10.90.0.0/24;
deny all;
proxy_pass 192.168.50.20:443;
}
}
Czytaj to jako fragment nowego listenera, a nie bezpośrednie zastąpienie działającej konfiguracji. Najpierw przejrzyj istniejące listenery i include, bo drugi listener na już zajętym porcie zawodzi przy reload, a nie w momencie żądania.
Zwróć uwagę, czego brakuje: żadnego listen ... ssl, żadnej dyrektywy certyfikatu. NGINX przekazuje zaszyfrowany strumień, a backend kończy TLS i przedstawia certyfikat, który weryfikuje klient. Klient, który nie przejdzie allowlisty, dostaje odrzuconą sesję TCP, a nie stronę HTTP 403, i każde narzędzie oczekujące kodu statusu zgłosi coś bezużytecznego.
Co allowlista obejmuje, a czego nie
Jeśli relay już wybiera backendy według nazwy serwera, ssl_preread i map mogą dalej wykonywać tę pracę, pod warunkiem że moduł jest dostępny. Nazwę nadal dostarcza klient, a nic w przedstawianiu nazwy nie dowodzi, że klient dołączył do VPN.
Reguła z przykładu obejmuje cały listener stream. To czyni ją nieodpowiednią dla jednego punktu wejścia obsługującego mieszankę witryn publicznych i witryn tylko dla VPN, gdzie potrzebny byłby wyjątek dla każdej nazwy; osobne listenery są zwykle jaśniejsze niż polityka zależna od nazwy, której nikt nie potrafi przeczytać.
Warto wymienić jeszcze dwie luki. Dopasowanie prefiksu nic nie mówi o tym, przez który interfejs przyszedł pakiet, a reguła HTTP gdzie indziej nie może ograniczyć tego listenera. Oba są powodem, by trzymać politykę wejścia na poziomie hosta w obrazie, zamiast traktować jedną linię allow jako całą granicę. Zapisz granicę jako dwie kontrole, które muszą się zgadzać, aby każda zmiana w którejkolwiek z nich była przeglądana.
Czyj adres NGINX naprawdę widzi?
Balanser obciążenia, inny proxy lub source NAT mogą postawić pośrednika przed NGINX, więc obserwowany peer nie jest wewnętrznym adresem klienta VPN. Zbadaj rzeczywistą ścieżkę, zanim wybierzesz prefiks, bo allowlista napisana dla złego adresu albo wpuszcza wszystkich za translatorem, albo nikogo.
Protokół PROXY i obsługa prawdziwego IP to uzasadnione odpowiedzi i należy je konfigurować tylko dla zgodnych, wyraźnie zaufanych nadawców. Oba mechanizmy wierzą w to, co mówi nadawca, i właśnie dlatego lista nadawców musi być krótka. Zaufanie nagłówkowi tożsamości od dowolnego klienta internetowego nie czyni informacji o źródle znów wiarygodnymi; zamienia poprawną odmowę w sfałszowane dopuszczenie.
Przetestuj oba wyniki przed reloadem
Zweryfikuj konfigurację, wykonaj reload, a następnie przetestuj dwa razy: nową dozwoloną sesję, która musi działać, i odrzuconą, która nie może. Zachowaj normalną weryfikację certyfikatu backendu w dozwolonym teście, bo relay, który się łączy, ale nie potrafi zweryfikować backendu, rozwiązał jeden problem i stworzył drugi.
nginx -t
ss -tnp | grep ':443'
Sprawdź też trasę do backendu i odpowiedź osobno. Przejście allowlisty dowodzi tylko, że NGINX zaakceptował sesję; nie może zmusić nieosiągalnego backendu do odpowiedzi ani naprawić drogi powrotnej, której brakowało przed rozpoczęciem.